Make primitive array factory functions constructors

This commit is contained in:
Alexander Udalov
2016-01-20 23:14:06 +03:00
parent 4b03adaa57
commit 9e8b6571f4
7 changed files with 203 additions and 223 deletions
@@ -25,8 +25,8 @@ import com.intellij.util.ArrayUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.Stack;
import kotlin.Pair;
import kotlin.collections.CollectionsKt;
import kotlin.Unit;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -56,6 +56,8 @@ import org.jetbrains.kotlin.jvm.bindingContextSlices.BindingContextSlicesKt;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
import org.jetbrains.kotlin.name.ClassId;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
@@ -78,11 +80,13 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
import org.jetbrains.kotlin.resolve.scopes.receivers.*;
import org.jetbrains.kotlin.serialization.deserialization.FindClassInModuleKt;
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.TypeProjection;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
import org.jetbrains.kotlin.utils.StringsKt;
import org.jetbrains.org.objectweb.asm.Label;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
import org.jetbrains.org.objectweb.asm.Opcodes;
@@ -97,8 +101,7 @@ import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
import static org.jetbrains.kotlin.resolve.BindingContext.*;
import static org.jetbrains.kotlin.resolve.BindingContextUtils.*;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isObject;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionExpression;
import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral;
@@ -3345,7 +3348,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
Type type = expressionType(expression);
if (type.getSort() == Type.ARRAY) {
//noinspection ConstantConditions
return generateNewArray(expression, bindingContext.getType(expression));
return generateNewArray(expression, bindingContext.getType(expression), resolvedCall);
}
return generateConstructorCall(resolvedCall, type);
@@ -3391,20 +3394,54 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
});
}
public StackValue generateNewArray(@NotNull KtCallExpression expression, @NotNull final KotlinType arrayType) {
assert expression.getValueArguments().size() == 1 : "Size argument expected";
public StackValue generateNewArray(
@NotNull KtCallExpression expression, @NotNull final KotlinType arrayType, @NotNull ResolvedCall<?> resolvedCall
) {
List<KtValueArgument> args = expression.getValueArguments();
assert args.size() == 1 || args.size() == 2 : "Unknown constructor called: " + args.size() + " arguments";
final KtExpression sizeExpression = expression.getValueArguments().get(0).getArgumentExpression();
Type type = typeMapper.mapType(arrayType);
if (args.size() == 1) {
final KtExpression sizeExpression = args.get(0).getArgumentExpression();
return StackValue.operation(typeMapper.mapType(arrayType), new Function1<InstructionAdapter, Unit>() {
@Override
public Unit invoke(InstructionAdapter v) {
gen(sizeExpression, Type.INT_TYPE);
newArrayInstruction(arrayType);
return Unit.INSTANCE;
}
});
}
return StackValue.operation(type, new Function1<InstructionAdapter, Unit>() {
@Override
public Unit invoke(InstructionAdapter v) {
gen(sizeExpression, Type.INT_TYPE);
newArrayInstruction(arrayType);
return Unit.INSTANCE;
final ConstructorDescriptor constructor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor();
final ClassDescriptor intrinsicConstructors =
FindClassInModuleKt.findClassAcrossModuleDependencies(
getContainingModule(context.getContextDescriptor()),
ClassId.topLevel(new FqName("kotlin.jvm.internal.IntrinsicArrayConstructors"))
);
// TODO: do not depend on a class from the runtime
assert intrinsicConstructors != null : "Class IntrinsicArrayConstructors is not found";
ResolvedCall<?> fakeResolvedCall = new DelegatingResolvedCall<CallableDescriptor>(resolvedCall) {
private final CallableDescriptor descriptor;
{
Collection<FunctionDescriptor> functions = intrinsicConstructors.getUnsubstitutedMemberScope().getContributedFunctions(
constructor.getContainingDeclaration().getName(), NoLookupLocation.FROM_BACKEND);
assert functions.size() == 1
: "IntrinsicArrayConstructors does not have a single constructor for " +
constructor.getContainingDeclaration().getName() + ":\n" + StringsKt.join(functions, "\n");
descriptor = CollectionsKt.single(functions);
}
});
@NotNull
@Override
public CallableDescriptor getResultingDescriptor() {
return descriptor;
}
};
return invokeFunction(fakeResolvedCall, StackValue.singleton(intrinsicConstructors, typeMapper));
}
public void newArrayInstruction(@NotNull KotlinType arrayType) {
@@ -110,7 +110,7 @@ public class FunctionReferenceGenerationStrategy extends FunctionGenerationStrat
if (referencedFunction instanceof ConstructorDescriptor) {
if (returnType.getSort() == Type.ARRAY) {
//noinspection ConstantConditions
result = codegen.generateNewArray(fakeExpression, referencedFunction.getReturnType());
result = codegen.generateNewArray(fakeExpression, referencedFunction.getReturnType(), fakeResolvedCall);
}
else {
result = codegen.generateConstructorCall(fakeResolvedCall, returnType);