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:
Alexander Udalov
2013-04-21 22:00:32 +04:00
parent db65237989
commit 1eeaaad05d
6 changed files with 85 additions and 109 deletions
@@ -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"
}
@@ -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");