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:
@@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+17
-36
@@ -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)!!
|
||||
}
|
||||
+10
@@ -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");
|
||||
|
||||
-10
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user