From de8b2b3668b1385c9d9e68053118a13c860d83c1 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 13 May 2014 19:57:08 +0400 Subject: [PATCH] Fix generic signature for SAM adapters and constructors SAM-related code in codegen was using JavaClassDescriptor directly, which has an erased signature. Create and use a new abstraction SamType which has a full generic signature of a type which was used in the SAM construct --- .../jetbrains/jet/codegen/ClosureCodegen.java | 38 +++++----- .../jet/codegen/ExpressionCodegen.java | 40 +++++----- .../org/jetbrains/jet/codegen/SamType.java | 75 +++++++++++++++++++ .../jet/codegen/SamWrapperClasses.java | 13 ++-- .../jet/codegen/SamWrapperCodegen.java | 30 ++++---- .../binding/CodegenAnnotatingVisitor.java | 53 +++++-------- .../jet/codegen/binding/CodegenBinding.java | 4 +- .../jet/codegen/inline/MethodInliner.java | 9 ++- .../sam/adapters/genericSignature.java | 8 ++ .../sam/adapters/genericSignature.kt | 5 ++ .../sam/samConstructorGenericSignature.java | 9 +++ .../sam/samConstructorGenericSignature.kt | 8 ++ .../BlackBoxWithJavaCodegenTestGenerated.java | 10 +++ .../java/sam/SingleAbstractMethodUtils.java | 10 --- 14 files changed, 202 insertions(+), 110 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/SamType.java create mode 100644 compiler/testData/codegen/boxWithJava/sam/adapters/genericSignature.java create mode 100644 compiler/testData/codegen/boxWithJava/sam/adapters/genericSignature.kt create mode 100644 compiler/testData/codegen/boxWithJava/sam/samConstructorGenericSignature.java create mode 100644 compiler/testData/codegen/boxWithJava/sam/samConstructorGenericSignature.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 51bb690f0ef..f920c59cf19 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -32,7 +32,6 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.java.JvmAbi; -import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; @@ -54,7 +53,7 @@ import static org.jetbrains.org.objectweb.asm.Opcodes.*; public class ClosureCodegen extends ParentCodegenAwareImpl { private final PsiElement fun; private final FunctionDescriptor funDescriptor; - private final ClassDescriptor samInterface; + private final SamType samType; private final JetType superClassType; private final List superInterfaceTypes; private final CodegenContext context; @@ -70,7 +69,7 @@ public class ClosureCodegen extends ParentCodegenAwareImpl { @NotNull GenerationState state, @NotNull PsiElement fun, @NotNull FunctionDescriptor funDescriptor, - @Nullable ClassDescriptor samInterface, + @Nullable SamType samType, @NotNull CodegenContext parentContext, @NotNull KotlinSyntheticClass.Kind syntheticClassKind, @NotNull LocalLookup localLookup, @@ -81,14 +80,14 @@ public class ClosureCodegen extends ParentCodegenAwareImpl { this.fun = fun; this.funDescriptor = funDescriptor; - this.samInterface = samInterface; + this.samType = samType; this.context = parentContext.intoClosure(funDescriptor, localLookup, typeMapper); this.syntheticClassKind = syntheticClassKind; this.strategy = strategy; ClassDescriptor classDescriptor = anonymousClassForFunction(bindingContext, funDescriptor); - if (samInterface == null) { + if (samType == null) { this.superInterfaceTypes = new ArrayList(); JetType superClassType = null; @@ -107,8 +106,7 @@ public class ClosureCodegen extends ParentCodegenAwareImpl { this.superClassType = superClassType; } else { - // TODO: getDefaultType() is incorrect here - this.superInterfaceTypes = Collections.singletonList(samInterface.getDefaultType()); + this.superInterfaceTypes = Collections.singletonList(samType.getType()); this.superClassType = KotlinBuiltIns.getInstance().getAnyType(); } @@ -123,15 +121,18 @@ public class ClosureCodegen extends ParentCodegenAwareImpl { public void gen() { ClassBuilder cv = state.getFactory().newVisitor(asmType, fun.getContainingFile()); - FunctionDescriptor interfaceFunction; - if (samInterface == null) { - interfaceFunction = getInvokeFunction(funDescriptor); + FunctionDescriptor erasedInterfaceFunction; + if (samType == null) { + erasedInterfaceFunction = getErasedInvokeFunction(funDescriptor); } else { - interfaceFunction = SingleAbstractMethodUtils.getAbstractMethodOfSamInterface(samInterface); + erasedInterfaceFunction = samType.getAbstractMethod().getOriginal(); } BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS); + if (samType != null) { + typeMapper.writeFormalTypeParameters(samType.getType().getConstructor().getParameters(), sw); + } sw.writeSuperclass(); Type superClassAsmType = typeMapper.mapSupertype(superClassType, sw); sw.writeSuperclassEnd(); @@ -155,8 +156,9 @@ public class ClosureCodegen extends ParentCodegenAwareImpl { writeKotlinSyntheticClassAnnotation(cv, syntheticClassKind); - JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature(funDescriptor).replaceName(interfaceFunction.getName().toString()); - generateBridge(cv, typeMapper.mapSignature(interfaceFunction).getAsmMethod(), jvmMethodSignature.getAsmMethod()); + JvmMethodSignature jvmMethodSignature = + typeMapper.mapSignature(funDescriptor).replaceName(erasedInterfaceFunction.getName().toString()); + generateBridge(cv, typeMapper.mapSignature(erasedInterfaceFunction).getAsmMethod(), jvmMethodSignature.getAsmMethod()); FunctionCodegen fc = new FunctionCodegen(context, cv, state, getParentCodegen()); fc.generateMethod(fun, jvmMethodSignature, funDescriptor, strategy); @@ -330,12 +332,12 @@ public class ClosureCodegen extends ParentCodegenAwareImpl { return argTypes; } - public static FunctionDescriptor getInvokeFunction(FunctionDescriptor funDescriptor) { - int paramCount = funDescriptor.getValueParameters().size(); - KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance(); + @NotNull + public static FunctionDescriptor getErasedInvokeFunction(@NotNull FunctionDescriptor funDescriptor) { + int arity = funDescriptor.getValueParameters().size(); ClassDescriptor funClass = funDescriptor.getReceiverParameter() == null - ? builtIns.getFunction(paramCount) - : builtIns.getExtensionFunction(paramCount); + ? KotlinBuiltIns.getInstance().getFunction(arity) + : KotlinBuiltIns.getInstance().getExtensionFunction(arity); return funClass.getDefaultType().getMemberScope().getFunctions(Name.identifier("invoke")).iterator().next(); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 7c9b6620a2f..8a494984dd7 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -50,7 +50,6 @@ import org.jetbrains.jet.lang.resolve.constants.IntegerValueConstant; import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstant; import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants; import org.jetbrains.jet.lang.resolve.java.JvmAbi; -import org.jetbrains.jet.lang.resolve.java.descriptor.JavaClassDescriptor; import org.jetbrains.jet.lang.resolve.java.descriptor.SamConstructorDescriptor; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.receivers.*; @@ -221,9 +220,9 @@ public class ExpressionCodegen extends JetVisitor implem try { if (selector instanceof JetExpression) { JetExpression expression = (JetExpression) selector; - JavaClassDescriptor samInterface = bindingContext.get(CodegenBinding.SAM_VALUE, expression); - if (samInterface != null) { - return genSamInterfaceValue(expression, samInterface, visitor); + SamType samType = bindingContext.get(CodegenBinding.SAM_VALUE, expression); + if (samType != null) { + return genSamInterfaceValue(expression, samType, visitor); } } @@ -1304,14 +1303,14 @@ public class ExpressionCodegen extends JetVisitor implem @NotNull private StackValue genClosure( JetDeclarationWithBody declaration, - @Nullable ClassDescriptor samInterfaceClass, + @Nullable SamType samType, @NotNull KotlinSyntheticClass.Kind kind ) { FunctionDescriptor descriptor = bindingContext.get(FUNCTION, declaration); assert descriptor != null : "Function is not resolved to descriptor: " + declaration.getText(); ClosureCodegen closureCodegen = new ClosureCodegen( - state, declaration, descriptor, samInterfaceClass, context, kind, this, + state, declaration, descriptor, samType, context, kind, this, new FunctionGenerationStrategy.FunctionDefault(state, descriptor, declaration), parentCodegen ); closureCodegen.gen(); @@ -1885,7 +1884,7 @@ public class ExpressionCodegen extends JetVisitor implem assert callee != null; ResolvedCall resolvedCall = resolvedCall(callee); - DeclarationDescriptor funDescriptor = resolvedCall.getResultingDescriptor(); + CallableDescriptor funDescriptor = resolvedCall.getResultingDescriptor(); if (!(funDescriptor instanceof FunctionDescriptor)) { throw new UnsupportedOperationException("unknown type of callee descriptor: " + funDescriptor); @@ -1898,18 +1897,22 @@ public class ExpressionCodegen extends JetVisitor implem } Call call = bindingContext.get(CALL, expression.getCalleeExpression()); - if (funDescriptor instanceof SimpleFunctionDescriptor) { - SimpleFunctionDescriptor original = ((SimpleFunctionDescriptor) funDescriptor).getOriginal(); - if (original instanceof SamConstructorDescriptor) { - return invokeSamConstructor(expression, resolvedCall, ((SamConstructorDescriptor) original).getBaseForSynthesized()); - } + if (funDescriptor.getOriginal() instanceof SamConstructorDescriptor) { + //noinspection ConstantConditions + SamType samType = SamType.create(funDescriptor.getReturnType()); + assert samType != null : "SamType is not created for SAM constructor: " + funDescriptor; + return invokeSamConstructor(expression, resolvedCall, samType); } return invokeFunction(call, receiver, resolvedCall); } @NotNull - private StackValue invokeSamConstructor(JetCallExpression expression, ResolvedCall resolvedCall, JavaClassDescriptor samInterface) { + private StackValue invokeSamConstructor( + @NotNull JetCallExpression expression, + @NotNull ResolvedCall resolvedCall, + @NotNull SamType samType + ) { List arguments = resolvedCall.getValueArgumentsByIndex(); if (arguments == null) { throw new IllegalStateException("Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor()); @@ -1924,27 +1927,26 @@ public class ExpressionCodegen extends JetVisitor implem JetExpression argumentExpression = valueArgument.getArgumentExpression(); assert argumentExpression != null : "getArgumentExpression() is null for " + expression.getText(); - return genSamInterfaceValue(argumentExpression, samInterface, this); + return genSamInterfaceValue(argumentExpression, samType, this); } @NotNull private StackValue genSamInterfaceValue( @NotNull JetExpression expression, - @NotNull JavaClassDescriptor samInterface, + @NotNull SamType samType, @NotNull JetVisitor visitor ) { if (expression instanceof JetFunctionLiteralExpression) { - return genClosure(((JetFunctionLiteralExpression) expression).getFunctionLiteral(), samInterface, + return genClosure(((JetFunctionLiteralExpression) expression).getFunctionLiteral(), samType, KotlinSyntheticClass.Kind.SAM_LAMBDA); } - Type asmType = state.getSamWrapperClasses().getSamWrapperClass(samInterface, expression.getContainingJetFile()); + Type asmType = state.getSamWrapperClasses().getSamWrapperClass(samType, expression.getContainingJetFile()); v.anew(asmType); v.dup(); - @SuppressWarnings("ConstantConditions") - Type functionType = typeMapper.mapType(samInterface.getFunctionTypeForSamInterface()); + Type functionType = typeMapper.mapType(samType.getKotlinFunctionType()); expression.accept(visitor, StackValue.none()).put(functionType, v); Label ifNonNull = new Label(); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/SamType.java b/compiler/backend/src/org/jetbrains/jet/codegen/SamType.java new file mode 100644 index 00000000000..24f4b9116ce --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/SamType.java @@ -0,0 +1,75 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; +import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor; +import org.jetbrains.jet.lang.resolve.java.descriptor.JavaClassDescriptor; +import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils; +import org.jetbrains.jet.lang.types.JetType; + +public class SamType { + public static SamType create(@NotNull JetType originalType) { + if (!SingleAbstractMethodUtils.isSamType(originalType)) return null; + return new SamType(originalType); + } + + private final JetType type; + + private SamType(@NotNull JetType type) { + this.type = type; + } + + @NotNull + public JetType getType() { + return type; + } + + @NotNull + public JavaClassDescriptor getJavaClassDescriptor() { + ClassifierDescriptor classifier = type.getConstructor().getDeclarationDescriptor(); + assert classifier instanceof JavaClassDescriptor : "Sam interface not a Java class: " + classifier; + return (JavaClassDescriptor) classifier; + } + + @NotNull + public JetType getKotlinFunctionType() { + //noinspection ConstantConditions + return getJavaClassDescriptor().getFunctionTypeForSamInterface(); + } + + @NotNull + public SimpleFunctionDescriptor getAbstractMethod() { + return (SimpleFunctionDescriptor) SingleAbstractMethodUtils.getAbstractMembers(type).get(0); + } + + @Override + public boolean equals(Object o) { + return o instanceof SamType && type.equals(((SamType) o).type); + } + + @Override + public int hashCode() { + return type.hashCode(); + } + + @Override + public String toString() { + return "SamType(" + type + ")"; + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/SamWrapperClasses.java b/compiler/backend/src/org/jetbrains/jet/codegen/SamWrapperClasses.java index 944bf6b0060..0d88829d491 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/SamWrapperClasses.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/SamWrapperClasses.java @@ -21,29 +21,28 @@ import com.intellij.openapi.util.Factory; import com.intellij.openapi.util.Pair; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.lang.psi.JetFile; -import org.jetbrains.jet.lang.resolve.java.descriptor.JavaClassDescriptor; +import org.jetbrains.org.objectweb.asm.Type; import java.util.Map; public class SamWrapperClasses { private final GenerationState state; - private final Map, Type> samInterfaceToWrapperClass = Maps.newHashMap(); + private final Map, Type> samInterfaceToWrapperClass = Maps.newHashMap(); - public SamWrapperClasses(GenerationState state) { + public SamWrapperClasses(@NotNull GenerationState state) { this.state = state; } @NotNull - public Type getSamWrapperClass(@NotNull final JavaClassDescriptor samInterface, @NotNull final JetFile file) { - return ContainerUtil.getOrCreate(samInterfaceToWrapperClass, Pair.create(samInterface, file), + public Type getSamWrapperClass(@NotNull final SamType samType, @NotNull final JetFile file) { + return ContainerUtil.getOrCreate(samInterfaceToWrapperClass, Pair.create(samType, file), new Factory() { @Override public Type create() { - return new SamWrapperCodegen(state, samInterface).genWrapper(file); + return new SamWrapperCodegen(state, samType).genWrapper(file); } }); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/SamWrapperCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/SamWrapperCodegen.java index 582419d5f44..98bfde3a40c 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/SamWrapperCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/SamWrapperCodegen.java @@ -27,7 +27,6 @@ import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; import org.jetbrains.jet.lang.resolve.java.descriptor.JavaClassDescriptor; -import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.types.JetType; @@ -46,12 +45,12 @@ public class SamWrapperCodegen { private final GenerationState state; private final JetTypeMapper typeMapper; - private final JavaClassDescriptor samInterface; + private final SamType samType; - public SamWrapperCodegen(@NotNull GenerationState state, @NotNull JavaClassDescriptor samInterface) { + public SamWrapperCodegen(@NotNull GenerationState state, @NotNull SamType samType) { this.state = state; this.typeMapper = state.getTypeMapper(); - this.samInterface = samInterface; + this.samType = samType; } public Type genWrapper(@NotNull JetFile file) { @@ -59,10 +58,9 @@ public class SamWrapperCodegen { Type asmType = Type.getObjectType(getWrapperName(file)); // e.g. (T, T) -> Int - JetType functionType = samInterface.getFunctionTypeForSamInterface(); - assert functionType != null : samInterface.toString(); + JetType functionType = samType.getKotlinFunctionType(); // e.g. compare(T, T) - SimpleFunctionDescriptor interfaceFunction = SingleAbstractMethodUtils.getAbstractMethodOfSamInterface(samInterface); + SimpleFunctionDescriptor erasedInterfaceFunction = samType.getAbstractMethod().getOriginal(); ClassBuilder cv = state.getFactory().newVisitor(asmType, file); cv.defineClass(file, @@ -71,7 +69,7 @@ public class SamWrapperCodegen { asmType.getInternalName(), null, OBJECT_TYPE.getInternalName(), - new String[]{ typeMapper.mapType(samInterface).getInternalName() } + new String[]{ typeMapper.mapType(samType.getType()).getInternalName() } ); cv.visitSource(file.getName(), null); @@ -88,7 +86,7 @@ public class SamWrapperCodegen { null); generateConstructor(asmType, functionAsmType, cv); - generateMethod(asmType, functionAsmType, cv, interfaceFunction, functionType); + generateMethod(asmType, functionAsmType, cv, erasedInterfaceFunction, functionType); cv.done(); @@ -120,7 +118,7 @@ public class SamWrapperCodegen { Type ownerType, Type functionType, ClassBuilder cv, - SimpleFunctionDescriptor interfaceFunction, + SimpleFunctionDescriptor erasedInterfaceFunction, JetType functionJetType ) { // using static context to avoid creating ClassDescriptor and everything else @@ -129,14 +127,18 @@ public class SamWrapperCodegen { FunctionDescriptor invokeFunction = functionJetType.getMemberScope() .getFunctions(Name.identifier("invoke")).iterator().next().getOriginal(); StackValue functionField = StackValue.field(functionType, ownerType, FUNCTION_FIELD_NAME, false); - codegen.genDelegate(interfaceFunction, invokeFunction, functionField); + codegen.genDelegate(erasedInterfaceFunction, invokeFunction, functionField); } + @NotNull private String getWrapperName(@NotNull JetFile containingFile) { FqName packageClassFqName = PackageClassUtils.getPackageClassFqName(containingFile.getPackageFqName()); String packageInternalName = JvmClassName.byFqNameWithoutInnerClasses(packageClassFqName).getInternalName(); - return packageInternalName + "$sam$" + samInterface.getName().asString() + "$" + - Integer.toHexString(JvmCodegenUtil.getPathHashCode(containingFile.getVirtualFile()) * 31 + DescriptorUtils.getFqNameSafe( - samInterface).hashCode()); + JavaClassDescriptor descriptor = samType.getJavaClassDescriptor(); + return packageInternalName + "$sam$" + descriptor.getName().asString() + "$" + + Integer.toHexString( + JvmCodegenUtil.getPathHashCode(containingFile.getVirtualFile()) * 31 + + DescriptorUtils.getFqNameSafe(descriptor).hashCode() + ); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenAnnotatingVisitor.java b/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenAnnotatingVisitor.java index dbceafbfbe0..9e18d8b1303 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenAnnotatingVisitor.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenAnnotatingVisitor.java @@ -24,6 +24,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.codegen.JvmFunctionImplTypes; import org.jetbrains.jet.codegen.SamCodegenUtil; +import org.jetbrains.jet.codegen.SamType; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.impl.ClassDescriptorImpl; @@ -37,8 +38,6 @@ import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument; import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; -import org.jetbrains.jet.lang.resolve.java.descriptor.JavaClassDescriptor; -import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.JetScope; @@ -401,28 +400,21 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { public void visitCallExpression(@NotNull JetCallExpression expression) { super.visitCallExpression(expression); ResolvedCall call = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression()); - if (call == null) { - return; - } + if (call == null) return; CallableDescriptor descriptor = call.getResultingDescriptor(); - if (!(descriptor instanceof FunctionDescriptor)) { - return; - } - FunctionDescriptor original = SamCodegenUtil.getOriginalIfSamAdapter((FunctionDescriptor) descriptor); + if (!(descriptor instanceof FunctionDescriptor)) return; + + FunctionDescriptor original = SamCodegenUtil.getOriginalIfSamAdapter((FunctionDescriptor) descriptor); + if (original == null) return; - if (original == null) { - return; - } List valueArguments = call.getValueArgumentsByIndex(); if (valueArguments == null) { throw new IllegalStateException("Failed to arrange value arguments by index: " + descriptor); } for (ValueParameterDescriptor valueParameter : original.getValueParameters()) { - JavaClassDescriptor samInterface = getInterfaceIfSamType(valueParameter.getType()); - if (samInterface == null) { - continue; - } + SamType samType = SamType.create(valueParameter.getType()); + if (samType == null) continue; ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameter.getIndex()); assert resolvedValueArgument instanceof ExpressionValueArgument : resolvedValueArgument; @@ -431,7 +423,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { JetExpression argumentExpression = valueArgument.getArgumentExpression(); assert argumentExpression != null : valueArgument.asElement().getText(); - bindingTrace.record(CodegenBinding.SAM_VALUE, argumentExpression, samInterface); + bindingTrace.record(CodegenBinding.SAM_VALUE, argumentExpression, samType); } } @@ -445,15 +437,15 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { FunctionDescriptor original = SamCodegenUtil.getOriginalIfSamAdapter((FunctionDescriptor) operationDescriptor); if (original == null) return; - JavaClassDescriptor samInterfaceOfParameter = getInterfaceIfSamType(original.getValueParameters().get(0).getType()); - if (samInterfaceOfParameter == null) return; + SamType samType = SamType.create(original.getValueParameters().get(0).getType()); + if (samType == null) return; IElementType token = expression.getOperationToken(); if (BINARY_OPERATIONS.contains(token)) { - bindingTrace.record(CodegenBinding.SAM_VALUE, expression.getRight(), samInterfaceOfParameter); + bindingTrace.record(CodegenBinding.SAM_VALUE, expression.getRight(), samType); } else if (token == IN_KEYWORD || token == NOT_IN) { - bindingTrace.record(CodegenBinding.SAM_VALUE, expression.getLeft(), samInterfaceOfParameter); + bindingTrace.record(CodegenBinding.SAM_VALUE, expression.getLeft(), samType); } } @@ -471,31 +463,20 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { List indexExpressions = expression.getIndexExpressions(); List parameters = original.getValueParameters(); for (ValueParameterDescriptor valueParameter : parameters) { - JavaClassDescriptor samInterface = getInterfaceIfSamType(valueParameter.getType()); - if (samInterface == null) continue; + SamType samType = SamType.create(valueParameter.getType()); + if (samType == null) continue; if (isSetter && valueParameter.getIndex() == parameters.size() - 1) { PsiElement parent = expression.getParent(); if (parent instanceof JetBinaryExpression && ((JetBinaryExpression) parent).getOperationToken() == EQ) { JetExpression right = ((JetBinaryExpression) parent).getRight(); - bindingTrace.record(CodegenBinding.SAM_VALUE, right, samInterface); + bindingTrace.record(CodegenBinding.SAM_VALUE, right, samType); } } else { JetExpression indexExpression = indexExpressions.get(valueParameter.getIndex()); - bindingTrace.record(CodegenBinding.SAM_VALUE, indexExpression, samInterface); + bindingTrace.record(CodegenBinding.SAM_VALUE, indexExpression, samType); } } } - - @Nullable - private static JavaClassDescriptor getInterfaceIfSamType(@NotNull JetType originalType) { - if (!SingleAbstractMethodUtils.isSamType(originalType)) { - return null; - } - JavaClassDescriptor samInterface = - (JavaClassDescriptor) originalType.getConstructor().getDeclarationDescriptor(); - assert samInterface != null; - return samInterface; - } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenBinding.java b/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenBinding.java index 393d5234b41..8024ef79831 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenBinding.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenBinding.java @@ -19,6 +19,7 @@ package org.jetbrains.jet.codegen.binding; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.codegen.SamType; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.impl.ClassDescriptorImpl; @@ -26,7 +27,6 @@ import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.java.JvmAbi; -import org.jetbrains.jet.lang.resolve.java.descriptor.JavaClassDescriptor; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.JetScope; @@ -55,7 +55,7 @@ public class CodegenBinding { public static final WritableSlice> INNER_CLASSES = Slices.createSimpleSlice(); - public static final WritableSlice SAM_VALUE = Slices.createSimpleSlice(); + public static final WritableSlice SAM_VALUE = Slices.createSimpleSlice(); static { BasicWritableSlice.initSliceDebugNames(CodegenBinding.class); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java index cc5df6c4186..cc64c90d51e 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java @@ -19,6 +19,9 @@ package org.jetbrains.jet.codegen.inline; import com.google.common.collect.Lists; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.codegen.ClosureCodegen; +import org.jetbrains.jet.codegen.StackValue; +import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.org.objectweb.asm.Label; import org.jetbrains.org.objectweb.asm.MethodVisitor; import org.jetbrains.org.objectweb.asm.Opcodes; @@ -28,9 +31,6 @@ import org.jetbrains.org.objectweb.asm.commons.Method; import org.jetbrains.org.objectweb.asm.commons.RemappingMethodAdapter; import org.jetbrains.org.objectweb.asm.tree.*; import org.jetbrains.org.objectweb.asm.tree.analysis.*; -import org.jetbrains.jet.codegen.ClosureCodegen; -import org.jetbrains.jet.codegen.StackValue; -import org.jetbrains.jet.codegen.state.JetTypeMapper; import java.util.*; @@ -197,7 +197,8 @@ public class MethodInliner { result.addAllClassesToRemove(lambdaResult); //return value boxing/unboxing - Method bridge = typeMapper.mapSignature(ClosureCodegen.getInvokeFunction(info.getFunctionDescriptor())).getAsmMethod(); + Method bridge = + typeMapper.mapSignature(ClosureCodegen.getErasedInvokeFunction(info.getFunctionDescriptor())).getAsmMethod(); Method delegate = typeMapper.mapSignature(info.getFunctionDescriptor()).getAsmMethod(); StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), this); setInlining(false); diff --git a/compiler/testData/codegen/boxWithJava/sam/adapters/genericSignature.java b/compiler/testData/codegen/boxWithJava/sam/adapters/genericSignature.java new file mode 100644 index 00000000000..573a1260ed6 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/sam/adapters/genericSignature.java @@ -0,0 +1,8 @@ +import java.util.Arrays; +import java.util.Comparator; + +class JavaClass { + public static String foo(Comparator comparator) { + return Arrays.toString(comparator.getClass().getGenericInterfaces()); + } +} diff --git a/compiler/testData/codegen/boxWithJava/sam/adapters/genericSignature.kt b/compiler/testData/codegen/boxWithJava/sam/adapters/genericSignature.kt new file mode 100644 index 00000000000..c857a4ac1c4 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/sam/adapters/genericSignature.kt @@ -0,0 +1,5 @@ +fun box(): String { + val supertypes = JavaClass.foo { a, b -> a.compareTo(b) } + if (supertypes != "[java.util.Comparator]") return "Fail: $supertypes" + return "OK" +} diff --git a/compiler/testData/codegen/boxWithJava/sam/samConstructorGenericSignature.java b/compiler/testData/codegen/boxWithJava/sam/samConstructorGenericSignature.java new file mode 100644 index 00000000000..25856ed995a --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/sam/samConstructorGenericSignature.java @@ -0,0 +1,9 @@ +class JavaClass { + interface Computable { + T compute(); + } + + static T compute(Computable computable) { + return computable.compute(); + } +} diff --git a/compiler/testData/codegen/boxWithJava/sam/samConstructorGenericSignature.kt b/compiler/testData/codegen/boxWithJava/sam/samConstructorGenericSignature.kt new file mode 100644 index 00000000000..32913f5dbdf --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/sam/samConstructorGenericSignature.kt @@ -0,0 +1,8 @@ +import java.util.Arrays + +fun box(): String { + val r: JavaClass.Computable = JavaClass.Computable { "OK" } + val supertypes = Arrays.toString(r.getClass().getGenericInterfaces()) + if (supertypes != "[JavaClass.JavaClass\$Computable]") return "Fail: $supertypes" + return JavaClass.compute(r)!! +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java index 9511ffdebcc..178e38534cc 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java @@ -238,6 +238,11 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege doTestWithJava("compiler/testData/codegen/boxWithJava/sam/differentFqNames.kt"); } + @TestMetadata("samConstructorGenericSignature.kt") + public void testSamConstructorGenericSignature() throws Exception { + doTestWithJava("compiler/testData/codegen/boxWithJava/sam/samConstructorGenericSignature.kt"); + } + @TestMetadata("compiler/testData/codegen/boxWithJava/sam/adapters") @InnerTestClasses({Adapters.Operators.class}) public static class Adapters extends AbstractBlackBoxCodegenTest { @@ -265,6 +270,11 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege doTestWithJava("compiler/testData/codegen/boxWithJava/sam/adapters/fileFilter.kt"); } + @TestMetadata("genericSignature.kt") + public void testGenericSignature() throws Exception { + doTestWithJava("compiler/testData/codegen/boxWithJava/sam/adapters/genericSignature.kt"); + } + @TestMetadata("implementAdapter.kt") public void testImplementAdapter() throws Exception { doTestWithJava("compiler/testData/codegen/boxWithJava/sam/adapters/implementAdapter.kt"); diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java index b3b667240b5..cf6f5851379 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java @@ -285,16 +285,6 @@ public class SingleAbstractMethodUtils { return new TypeParameters(typeParameters, typeParametersSubstitutor); } - @NotNull - public static SimpleFunctionDescriptor getAbstractMethodOfSamType(@NotNull JetType type) { - return (SimpleFunctionDescriptor) getAbstractMembers(type).get(0); - } - - @NotNull - public static SimpleFunctionDescriptor getAbstractMethodOfSamInterface(@NotNull ClassDescriptor samInterface) { - return getAbstractMethodOfSamType(samInterface.getDefaultType()); - } - public static boolean isSamInterface(@NotNull JavaClass javaClass) { return getSamInterfaceMethod(javaClass) != null; }