Refactor method/constructor calls in codegen
- use ResolvedCall where possible - 'call' parameter to invokeMethodWithArguments was used only to generate callee, e.g. in "A()" where A is an expression which can be invoke()'d. In case of constructors and enum entry delegation specifiers there's no need to generate callee, so 'call' is made Nullable with a subsequent assert - remove generateJavaConstructorCall() method, since it did no useful work. Java constructor invocation is broken anyway and needs to be fixed (KT-3532) - minor code style / formatting issues fixed, several methods renamed to better reflect semantics
This commit is contained in:
@@ -21,7 +21,6 @@ import com.google.common.collect.Maps;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.Stack;
|
||||
@@ -45,7 +44,6 @@ import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastReceiver;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.*;
|
||||
@@ -1745,7 +1743,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
throw new CompilationException("Cannot resolve: " + callee.getText(), null, expression);
|
||||
}
|
||||
|
||||
|
||||
DeclarationDescriptor funDescriptor = resolvedCall.getResultingDescriptor();
|
||||
|
||||
if (!(funDescriptor instanceof FunctionDescriptor)) {
|
||||
@@ -1755,28 +1752,26 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
funDescriptor = accessableFunctionDescriptor((FunctionDescriptor) funDescriptor);
|
||||
|
||||
if (funDescriptor instanceof ConstructorDescriptor) {
|
||||
receiver = StackValue.receiver(resolvedCall, receiver, this, null);
|
||||
return generateConstructorCall(expression, (JetSimpleNameExpression) callee, receiver);
|
||||
return generateNewCall(expression, resolvedCall, receiver);
|
||||
}
|
||||
else {
|
||||
Call call = bindingContext.get(CALL, expression.getCalleeExpression());
|
||||
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
|
||||
VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall;
|
||||
ResolvedCallWithTrace<FunctionDescriptor> functionCall = variableAsFunctionResolvedCall.getFunctionCall();
|
||||
return invokeFunction(call, receiver, functionCall);
|
||||
}
|
||||
else {
|
||||
if (funDescriptor instanceof SimpleFunctionDescriptor) {
|
||||
ClassDescriptor samInterface = bindingContext.get(
|
||||
BindingContext.SAM_CONSTRUCTOR_TO_INTERFACE, ((SimpleFunctionDescriptor) funDescriptor).getOriginal());
|
||||
|
||||
if (samInterface != null) {
|
||||
return invokeSamConstructor(expression, resolvedCall, (SimpleFunctionDescriptor) funDescriptor, samInterface);
|
||||
}
|
||||
}
|
||||
return invokeFunction(call, receiver, resolvedCall);
|
||||
Call call = bindingContext.get(CALL, expression.getCalleeExpression());
|
||||
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
|
||||
VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall;
|
||||
ResolvedCallWithTrace<FunctionDescriptor> functionCall = variableAsFunctionResolvedCall.getFunctionCall();
|
||||
return invokeFunction(call, receiver, functionCall);
|
||||
}
|
||||
|
||||
if (funDescriptor instanceof SimpleFunctionDescriptor) {
|
||||
ClassDescriptor samInterface = bindingContext.get(
|
||||
BindingContext.SAM_CONSTRUCTOR_TO_INTERFACE, ((SimpleFunctionDescriptor) funDescriptor).getOriginal());
|
||||
|
||||
if (samInterface != null) {
|
||||
return invokeSamConstructor(expression, resolvedCall, (SimpleFunctionDescriptor) funDescriptor, samInterface);
|
||||
}
|
||||
}
|
||||
|
||||
return invokeFunction(call, receiver, resolvedCall);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -1992,27 +1987,18 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
}
|
||||
}
|
||||
|
||||
public void invokeMethodWithArguments(CallableMethod callableMethod, JetCallElement expression, StackValue receiver) {
|
||||
JetExpression calleeExpression = expression.getCalleeExpression();
|
||||
Call call = bindingContext.get(CALL, calleeExpression);
|
||||
ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, calleeExpression);
|
||||
|
||||
assert resolvedCall != null;
|
||||
assert call != null;
|
||||
invokeMethodWithArguments(callableMethod, resolvedCall, call, receiver);
|
||||
}
|
||||
|
||||
|
||||
private void invokeMethodWithArguments(
|
||||
public void invokeMethodWithArguments(
|
||||
@NotNull CallableMethod callableMethod,
|
||||
@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall,
|
||||
@NotNull Call call,
|
||||
@Nullable Call callToGenerateCallee,
|
||||
@NotNull StackValue receiver
|
||||
) {
|
||||
Type calleeType = callableMethod.getGenerateCalleeType();
|
||||
if (calleeType != null) {
|
||||
assert !callableMethod.isNeedsThis();
|
||||
gen(call.getCalleeExpression(), calleeType);
|
||||
assert callToGenerateCallee != null : "Call can't be null when generating callee: " + resolvedCall.getResultingDescriptor();
|
||||
gen(callToGenerateCallee.getCalleeExpression(), calleeType);
|
||||
}
|
||||
|
||||
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
|
||||
@@ -2984,76 +2970,56 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
}
|
||||
}
|
||||
|
||||
private StackValue generateConstructorCall(
|
||||
JetCallExpression expression,
|
||||
JetSimpleNameExpression constructorReference,
|
||||
StackValue receiver
|
||||
@NotNull
|
||||
private StackValue generateNewCall(
|
||||
@NotNull JetCallExpression expression,
|
||||
@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall,
|
||||
@NotNull StackValue receiver
|
||||
) {
|
||||
DeclarationDescriptor constructorDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, constructorReference);
|
||||
assert constructorDescriptor != null;
|
||||
PsiElement declaration = BindingContextUtils.descriptorToDeclaration(bindingContext, constructorDescriptor);
|
||||
Type type;
|
||||
if (declaration instanceof PsiMethod) {
|
||||
type = generateJavaConstructorCall(expression);
|
||||
Type type = expressionType(expression);
|
||||
if (type.getSort() == Type.ARRAY) {
|
||||
generateNewArray(expression);
|
||||
return StackValue.onStack(type);
|
||||
}
|
||||
else if (constructorDescriptor instanceof ConstructorDescriptor) {
|
||||
//noinspection ConstantConditions
|
||||
JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression);
|
||||
assert expressionType != null;
|
||||
type = typeMapper.mapType(expressionType);
|
||||
if (type.getSort() == Type.ARRAY) {
|
||||
generateNewArray(expression, expressionType);
|
||||
}
|
||||
else {
|
||||
v.anew(type);
|
||||
v.dup();
|
||||
|
||||
ClassDescriptor classDescriptor = ((ConstructorDescriptor) constructorDescriptor).getContainingDeclaration();
|
||||
return generateConstructorCall(resolvedCall, receiver, type);
|
||||
}
|
||||
|
||||
CallableMethod method = typeMapper.mapToCallableMethod((ConstructorDescriptor) constructorDescriptor);
|
||||
@NotNull
|
||||
private StackValue generateConstructorCall(
|
||||
@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall,
|
||||
@NotNull StackValue receiver,
|
||||
@NotNull Type type
|
||||
) {
|
||||
v.anew(type);
|
||||
v.dup();
|
||||
|
||||
receiver.put(receiver.type, v);
|
||||
receiver = StackValue.receiver(resolvedCall, receiver, this, null);
|
||||
receiver.put(receiver.type, v);
|
||||
|
||||
MutableClosure closure = bindingContext.get(CLOSURE, classDescriptor);
|
||||
ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor();
|
||||
MutableClosure closure = bindingContext.get(CLOSURE, constructorDescriptor.getContainingDeclaration());
|
||||
|
||||
if(receiver.type.getSort() != Type.VOID && (closure == null || closure.getCaptureThis() == null)) {
|
||||
v.pop();
|
||||
}
|
||||
|
||||
pushClosureOnStack(closure, true);
|
||||
invokeMethodWithArguments(method, expression, StackValue.none());
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("don't know how to generate this new expression");
|
||||
if (receiver.type.getSort() != Type.VOID && (closure == null || closure.getCaptureThis() == null)) {
|
||||
v.pop();
|
||||
}
|
||||
|
||||
pushClosureOnStack(closure, true);
|
||||
|
||||
CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor);
|
||||
invokeMethodWithArguments(method, resolvedCall, null, StackValue.none());
|
||||
|
||||
return StackValue.onStack(type);
|
||||
}
|
||||
|
||||
private Type generateJavaConstructorCall(JetCallExpression expression) {
|
||||
JetExpression callee = expression.getCalleeExpression();
|
||||
ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, callee);
|
||||
if (resolvedCall == null) {
|
||||
assert callee != null;
|
||||
throw new CompilationException("Cannot resolve: " + callee.getText(), null, expression);
|
||||
}
|
||||
public void generateNewArray(@NotNull JetCallExpression expression) {
|
||||
JetType arrayType = bindingContext.get(EXPRESSION_TYPE, expression);
|
||||
assert arrayType != null : "Array instantiation isn't type checked: " + expression.getText();
|
||||
|
||||
FunctionDescriptor descriptor = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
|
||||
ClassDescriptor javaClass = (ClassDescriptor) descriptor.getContainingDeclaration();
|
||||
Type type = asmType(javaClass.getDefaultType());
|
||||
v.anew(type);
|
||||
v.dup();
|
||||
CallableMethod callableMethod = typeMapper.mapToCallableMethod(
|
||||
descriptor,
|
||||
false,
|
||||
isCallInsideSameClassAsDeclared(descriptor, context),
|
||||
isCallInsideSameModuleAsDeclared(descriptor, context),
|
||||
OwnerKind.IMPLEMENTATION);
|
||||
invokeMethodWithArguments(callableMethod, expression, StackValue.none());
|
||||
return type;
|
||||
generateNewArray(expression, arrayType);
|
||||
}
|
||||
|
||||
public void generateNewArray(JetCallExpression expression, JetType arrayType) {
|
||||
private void generateNewArray(@NotNull JetCallExpression expression, @NotNull JetType arrayType) {
|
||||
List<JetExpression> args = new ArrayList<JetExpression>();
|
||||
for (ValueArgument va : expression.getValueArguments()) {
|
||||
args.add(va.getArgumentExpression());
|
||||
@@ -3061,15 +3027,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
args.addAll(expression.getFunctionLiteralArguments());
|
||||
|
||||
boolean isArray = KotlinBuiltIns.getInstance().isArray(arrayType);
|
||||
if (isArray) {
|
||||
// if (args.size() != 2 && !arrayType.getArguments().get(0).getType().isNullable()) {
|
||||
// throw new CompilationException("array constructor of non-nullable type requires two arguments");
|
||||
// }
|
||||
}
|
||||
else {
|
||||
if (args.size() != 1) {
|
||||
throw new CompilationException("primitive array constructor requires one argument", null, expression);
|
||||
}
|
||||
if (!isArray && args.size() != 1) {
|
||||
throw new CompilationException("primitive array constructor requires one argument", null, expression);
|
||||
}
|
||||
|
||||
if (isArray) {
|
||||
|
||||
@@ -1488,7 +1488,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
superCallable.invokeWithNotNullAssertion(codegen.v, state, resolvedCall);
|
||||
}
|
||||
else {
|
||||
codegen.invokeMethodWithArguments(superCallable, (JetCallElement) superCall, StackValue.none());
|
||||
codegen.invokeMethodWithArguments(superCallable, resolvedCall, null, StackValue.none());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1571,13 +1571,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
if (delegationSpecifiers.size() == 1 && !enumEntryNeedSubclass(state.getBindingContext(), enumConstant)) {
|
||||
JetDelegationSpecifier specifier = delegationSpecifiers.get(0);
|
||||
if (specifier instanceof JetDelegatorToSuperCall) {
|
||||
JetDelegatorToSuperCall superCall = (JetDelegatorToSuperCall) specifier;
|
||||
ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) bindingContext
|
||||
.get(BindingContext.REFERENCE_TARGET, superCall.getCalleeExpression().getConstructorReferenceExpression());
|
||||
assert constructorDescriptor != null;
|
||||
//noinspection SuspiciousMethodCalls
|
||||
ResolvedCall<? extends CallableDescriptor> resolvedCall =
|
||||
bindingContext.get(BindingContext.RESOLVED_CALL, ((JetDelegatorToSuperCall) specifier).getCalleeExpression());
|
||||
assert resolvedCall != null : "Enum entry delegation specifier is unresolved: " + specifier.getText();
|
||||
|
||||
ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor();
|
||||
CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor);
|
||||
codegen.invokeMethodWithArguments(method, superCall, StackValue.none());
|
||||
|
||||
codegen.invokeMethodWithArguments(method, resolvedCall, null, StackValue.none());
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("unsupported type of enum constant initializer: " + specifier);
|
||||
|
||||
@@ -25,7 +25,6 @@ import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||
import org.jetbrains.jet.lang.psi.JetCallExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -40,8 +39,7 @@ public class NewArray implements IntrinsicMethod {
|
||||
StackValue receiver,
|
||||
@NotNull GenerationState state
|
||||
) {
|
||||
codegen.generateNewArray((JetCallExpression) element,
|
||||
codegen.getBindingContext().get(BindingContext.EXPRESSION_TYPE, (JetExpression) element));
|
||||
codegen.generateNewArray((JetCallExpression) element);
|
||||
return StackValue.onStack(expectedType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
class A {
|
||||
public A() {}
|
||||
|
||||
public A(String x) {}
|
||||
|
||||
public A(long l, double z) {}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
fun box(): String {
|
||||
A()
|
||||
A("")
|
||||
A(0.toLong(), 0.0)
|
||||
return "OK"
|
||||
}
|
||||
+5
@@ -81,6 +81,11 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/boxWithJava/functions"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("constructor.kt")
|
||||
public void testConstructor() throws Exception {
|
||||
doTestWithJava("compiler/testData/codegen/boxWithJava/functions/constructor.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("referencesStaticInnerClassMethod.kt")
|
||||
public void testReferencesStaticInnerClassMethod() throws Exception {
|
||||
doTestWithJava("compiler/testData/codegen/boxWithJava/functions/referencesStaticInnerClassMethod.kt");
|
||||
|
||||
Reference in New Issue
Block a user