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
This commit is contained in:
Alexander Udalov
2014-05-13 19:57:08 +04:00
parent 51a16fe491
commit de8b2b3668
14 changed files with 202 additions and 110 deletions
@@ -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<JetType> 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>();
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();
}
}
@@ -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<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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<ResolvedValueArgument> 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<StackValue, StackValue> 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<StackValue, StackValue> 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();
@@ -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 + ")";
}
}
@@ -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<Pair<JavaClassDescriptor, JetFile>, Type> samInterfaceToWrapperClass = Maps.newHashMap();
private final Map<Pair<SamType, JetFile>, 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<Type>() {
@Override
public Type create() {
return new SamWrapperCodegen(state, samInterface).genWrapper(file);
return new SamWrapperCodegen(state, samType).genWrapper(file);
}
});
}
@@ -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()
);
}
}
@@ -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<ResolvedValueArgument> 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<JetExpression> indexExpressions = expression.getIndexExpressions();
List<ValueParameterDescriptor> 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;
}
}
@@ -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<ClassDescriptor, Collection<ClassDescriptor>> INNER_CLASSES = Slices.createSimpleSlice();
public static final WritableSlice<JetExpression, JavaClassDescriptor> SAM_VALUE = Slices.createSimpleSlice();
public static final WritableSlice<JetExpression, SamType> SAM_VALUE = Slices.createSimpleSlice();
static {
BasicWritableSlice.initSliceDebugNames(CodegenBinding.class);
@@ -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);
@@ -0,0 +1,8 @@
import java.util.Arrays;
import java.util.Comparator;
class JavaClass {
public static String foo(Comparator<String> comparator) {
return Arrays.toString(comparator.getClass().getGenericInterfaces());
}
}
@@ -0,0 +1,5 @@
fun box(): String {
val supertypes = JavaClass.foo { a, b -> a.compareTo(b) }
if (supertypes != "[java.util.Comparator<java.lang.String>]") return "Fail: $supertypes"
return "OK"
}
@@ -0,0 +1,9 @@
class JavaClass {
interface Computable<T> {
T compute();
}
static <T> T compute(Computable<T> computable) {
return computable.compute();
}
}
@@ -0,0 +1,8 @@
import java.util.Arrays
fun box(): String {
val r: JavaClass.Computable<String> = JavaClass.Computable { "OK" }
val supertypes = Arrays.toString(r.getClass().getGenericInterfaces())
if (supertypes != "[JavaClass.JavaClass\$Computable<java.lang.String>]") return "Fail: $supertypes"
return JavaClass.compute(r)!!
}
@@ -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");
@@ -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;
}