From 1e2eb6dfa1a687a6c50883823621f35d4b8d8846 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 2 Dec 2013 17:28:38 +0400 Subject: [PATCH] Special instructions added for calls and other constructs --- .../jet/lang/cfg/JetControlFlowBuilder.java | 23 +- .../cfg/JetControlFlowBuilderAdapter.java | 47 ++- .../jet/lang/cfg/JetControlFlowProcessor.java | 300 ++++++++++++------ .../cfg/pseudocode/InstructionVisitor.java | 12 +- .../JetControlFlowInstructionsGenerator.java | 55 +++- .../jet/lang/cfg/pseudocode/instructions.kt | 49 +++ .../cfg/arrayAccessExpression.instructions | 34 ++ .../testData/cfg/arrayAccessExpression.kt | 8 + .../cfg/backingFieldAccess.instructions | 47 +++ compiler/testData/cfg/backingFieldAccess.kt | 8 + .../cfg/incrementAtTheEnd.instructions | 21 ++ compiler/testData/cfg/incrementAtTheEnd.kt | 4 + compiler/testData/cfg/invoke.instructions | 18 ++ compiler/testData/cfg/invoke.kt | 3 + .../multiDeclarationWithError.instructions | 23 ++ .../testData/cfg/multiDeclarationWithError.kt | 4 + .../cfg/propertySafeCall.instructions | 18 ++ compiler/testData/cfg/propertySafeCall.kt | 3 + .../diagnostics/tests/LValueAssignment.kt | 2 +- .../jet/cfg/ControlFlowTestGenerated.java | 30 ++ 20 files changed, 594 insertions(+), 115 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions.kt create mode 100644 compiler/testData/cfg/arrayAccessExpression.instructions create mode 100644 compiler/testData/cfg/arrayAccessExpression.kt create mode 100644 compiler/testData/cfg/backingFieldAccess.instructions create mode 100644 compiler/testData/cfg/backingFieldAccess.kt create mode 100644 compiler/testData/cfg/incrementAtTheEnd.instructions create mode 100644 compiler/testData/cfg/incrementAtTheEnd.kt create mode 100644 compiler/testData/cfg/invoke.instructions create mode 100644 compiler/testData/cfg/invoke.kt create mode 100644 compiler/testData/cfg/multiDeclarationWithError.instructions create mode 100644 compiler/testData/cfg/multiDeclarationWithError.kt create mode 100644 compiler/testData/cfg/propertySafeCall.instructions create mode 100644 compiler/testData/cfg/propertySafeCall.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java index 0069892a3ce..a86a7ed2bfd 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java @@ -19,7 +19,11 @@ package org.jetbrains.jet.lang.cfg; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; +import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor; +import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; +import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import java.util.List; @@ -82,7 +86,24 @@ public interface JetControlFlowBuilder { // Reading values void loadUnit(@NotNull JetExpression expression); - void read(@NotNull JetElement element); + void loadConstant(@NotNull JetExpression expression, @Nullable CompileTimeConstant constant); + void createAnonymousObject(@NotNull JetObjectLiteralExpression expression); + void loadStringTemplate(@NotNull JetStringTemplateExpression expression); + + void readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor); + void readVariable(@NotNull JetExpression expression, @Nullable VariableDescriptor variableDescriptor); + + void call(@NotNull JetExpression expression, @NotNull ResolvedCall resolvedCall); + + enum PredefinedOperation { + AND, + OR, + NOT_NULL_ASSERTION + } + void predefinedOperation(@NotNull JetExpression expression, @Nullable PredefinedOperation operation); + + void compilationError(@NotNull JetElement element, @NotNull String message); + void write(@NotNull JetElement assignment, @NotNull JetElement lValue); // Other diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java index 4c69649f546..c3539e49ce8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java @@ -19,7 +19,11 @@ package org.jetbrains.jet.lang.cfg; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; +import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor; +import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; +import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import java.util.List; @@ -27,13 +31,48 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder { protected JetControlFlowBuilder builder; @Override - public void read(@NotNull JetElement element) { - builder.read(element); + public void loadUnit(@NotNull JetExpression expression) { + builder.loadUnit(expression); } @Override - public void loadUnit(@NotNull JetExpression expression) { - builder.loadUnit(expression); + public void loadConstant(@NotNull JetExpression expression, @Nullable CompileTimeConstant constant) { + builder.loadConstant(expression, constant); + } + + @Override + public void createAnonymousObject(@NotNull JetObjectLiteralExpression expression) { + builder.createAnonymousObject(expression); + } + + @Override + public void loadStringTemplate(@NotNull JetStringTemplateExpression expression) { + builder.loadStringTemplate(expression); + } + + @Override + public void readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor) { + builder.readThis(expression, parameterDescriptor); + } + + @Override + public void readVariable(@NotNull JetExpression expression, @Nullable VariableDescriptor variableDescriptor) { + builder.readVariable(expression, variableDescriptor); + } + + @Override + public void call(@NotNull JetExpression expression, @NotNull ResolvedCall resolvedCall) { + builder.call(expression, resolvedCall); + } + + @Override + public void predefinedOperation(@NotNull JetExpression expression, @Nullable PredefinedOperation operation) { + builder.predefinedOperation(expression, operation); + } + + @Override + public void compilationError(@NotNull JetElement element, @NotNull String message) { + builder.compilationError(element, message); } @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 5f281e033c1..ed6f10346de 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -26,21 +26,35 @@ import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowInstructionsGenerator import org.jetbrains.jet.lang.cfg.pseudocode.LocalFunctionDeclarationInstruction; import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeImpl; +import org.jetbrains.jet.lang.descriptors.*; 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.BindingTrace; +import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastReceiver; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument; +import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall; +import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor; import org.jetbrains.jet.lang.resolve.constants.BooleanValue; +import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver; +import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ThisReceiver; +import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.expressions.OperatorConventions; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; +import org.jetbrains.jet.lexer.JetToken; import org.jetbrains.jet.lexer.JetTokens; -import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import static org.jetbrains.jet.lang.cfg.JetControlFlowBuilder.PredefinedOperation.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*; public class JetControlFlowProcessor { @@ -153,8 +167,6 @@ public class JetControlFlowProcessor { @Override public void visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression) { - builder.read(expression); - JetExpression innerExpression = expression.getExpression(); if (innerExpression != null) { generateInstructions(innerExpression, inCondition); @@ -163,8 +175,6 @@ public class JetControlFlowProcessor { @Override public void visitAnnotatedExpression(@NotNull JetAnnotatedExpression expression) { - builder.read(expression); - JetExpression baseExpression = expression.getBaseExpression(); if (baseExpression != null) { generateInstructions(baseExpression, inCondition); @@ -173,17 +183,26 @@ public class JetControlFlowProcessor { @Override public void visitThisExpression(@NotNull JetThisExpression expression) { - builder.read(expression); + ResolvedCall resolvedCall = getResolvedCall(expression); + builder.readThis(expression, resolvedCall == null ? null : (ReceiverParameterDescriptor) resolvedCall.getResultingDescriptor()); } @Override public void visitConstantExpression(@NotNull JetConstantExpression expression) { - builder.read(expression); + CompileTimeConstant constant = trace.get(BindingContext.COMPILE_TIME_VALUE, expression); + builder.loadConstant(expression, constant); } @Override public void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression) { - builder.read(expression); + ResolvedCall resolvedCall = getResolvedCall(expression); + if (resolvedCall instanceof VariableAsFunctionResolvedCall) { + VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall; + generateCall(expression, variableAsFunctionResolvedCall.getVariableCall()); + } + else { + generateCall(expression); + } } @Override @@ -204,7 +223,8 @@ public class JetControlFlowProcessor { @SuppressWarnings("SuspiciousMethodCalls") @Override public void visitBinaryExpression(@NotNull JetBinaryExpression expression) { - IElementType operationType = expression.getOperationReference().getReferencedNameElementType(); + JetSimpleNameExpression operationReference = expression.getOperationReference(); + IElementType operationType = operationReference.getReferencedNameElementType(); JetExpression right = expression.getRight(); if (operationType == JetTokens.ANDAND) { generateInstructions(expression.getLeft(), true); @@ -215,7 +235,7 @@ public class JetControlFlowProcessor { } builder.bindLabel(resultLabel); if (!inCondition) { - builder.read(expression); + builder.predefinedOperation(expression, AND); } } else if (operationType == JetTokens.OROR) { @@ -227,51 +247,33 @@ public class JetControlFlowProcessor { } builder.bindLabel(resultLabel); if (!inCondition) { - builder.read(expression); + builder.predefinedOperation(expression, OR); } } else if (operationType == JetTokens.EQ) { - JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft()); if (right != null) { generateInstructions(right, false); } - if (left instanceof JetSimpleNameExpression) { - builder.write(expression, left); - } - else if (left instanceof JetArrayAccessExpression) { - JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left; - visitAssignToArrayAccess(expression, arrayAccessExpression); - } - else if (left instanceof JetQualifiedExpression) { - JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) left; - generateInstructions(qualifiedExpression.getReceiverExpression(), false); - generateInstructions(expression.getOperationReference(), false); - builder.write(expression, left); - } - else { - builder.unsupported(expression); // TODO - } + visitAssignment(expression.getLeft(), expression); } else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) { - JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft()); - if (left != null) { - generateInstructions(left, false); + if (generateCall(operationReference)) { + ResolvedCall resolvedCall = getResolvedCall(operationReference); + assert resolvedCall != null : "Generation succeeded, but no call is found: " + expression.getText(); + CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); + Name assignMethodName = OperatorConventions.getNameForOperationSymbol((JetToken) expression.getOperationToken()); + if (!descriptor.getName().equals(assignMethodName)) { + // plus() called, assignment needed + visitAssignment(expression.getLeft(), expression); + } } - if (right != null) { - generateInstructions(right, false); - } - if (left instanceof JetSimpleNameExpression || left instanceof JetArrayAccessExpression) { - generateInstructions(expression.getOperationReference(), false); - builder.write(expression, left); - } - else if (left != null) { - builder.unsupported(expression); // TODO + else { + generateBothArguments(expression); } } else if (operationType == JetTokens.ELVIS) { - builder.read(expression); generateInstructions(expression.getLeft(), false); - generateInstructions(expression.getOperationReference(), false); + generateInstructions(operationReference, false); Label afterElvis = builder.createUnboundLabel(); builder.jumpOnTrue(afterElvis); if (right != null) { @@ -280,22 +282,60 @@ public class JetControlFlowProcessor { builder.bindLabel(afterElvis); } else { - generateInstructions(expression.getLeft(), false); - if (right != null) { - generateInstructions(right, false); + if (!generateCall(operationReference)) { + generateBothArguments(expression); } - generateInstructions(expression.getOperationReference(), false); - builder.read(expression); } } - private void visitAssignToArrayAccess(JetBinaryExpression expression, JetArrayAccessExpression arrayAccessExpression) { - for (JetExpression index : arrayAccessExpression.getIndexExpressions()) { - generateInstructions(index, false); + private void generateBothArguments(JetBinaryExpression expression) { + JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft()); + if (left != null) { + generateInstructions(left, false); + } + JetExpression right = expression.getRight(); + if (right != null) { + generateInstructions(right, false); + } + } + + private void visitAssignment(JetExpression lhs, JetExpression parentExpression) { + JetExpression left = JetPsiUtil.deparenthesize(lhs); + if (left == null) { + builder.compilationError(lhs, "No lValue in assignment"); + return; + } + if (left instanceof JetSimpleNameExpression) { + // Do nothing, only record write below + } + else if (left instanceof JetArrayAccessExpression) { + generateArrayAccess((JetArrayAccessExpression) left); + } + else if (left instanceof JetQualifiedExpression) { + // read the receiver + generateInstructions(((JetQualifiedExpression) left).getReceiverExpression(), false); + } + else if (left instanceof JetProperty) { + // do nothing, just write below + } + else { + builder.unsupported(parentExpression); // TODO + } + + VariableDescriptor descriptor = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), left, false); + if (descriptor != null) { + builder.write(parentExpression, left); + } + } + + private void generateArrayAccess(JetArrayAccessExpression arrayAccessExpression) { + if (!generateCall(arrayAccessExpression)) { + for (JetExpression index : arrayAccessExpression.getIndexExpressions()) { + generateInstructions(index, false); + } + + generateInstructions(arrayAccessExpression.getArrayExpression(), false); } - generateInstructions(arrayAccessExpression.getArrayExpression(), false); - generateInstructions(expression.getOperationReference(), false); - builder.write(expression, arrayAccessExpression); // TODO : ??? } @Override @@ -308,16 +348,20 @@ public class JetControlFlowProcessor { String referencedName = operationSign.getReferencedName(); visitLabeledExpression(referencedName.substring(1), baseExpression); } - else { + else if (JetTokens.EXCLEXCL == operationType) { generateInstructions(baseExpression, false); - generateInstructions(operationSign, false); + builder.predefinedOperation(expression, NOT_NULL_ASSERTION); + } + else { + if (!generateCall(expression.getOperationReference())) { + generateInstructions(baseExpression, false); + } boolean incrementOrDecrement = isIncrementOrDecrement(operationType); if (incrementOrDecrement) { - builder.write(expression, baseExpression); + // We skip dup's and other subtleties here + visitAssignment(baseExpression, expression); } - - builder.read(expression); } } @@ -353,7 +397,7 @@ public class JetControlFlowProcessor { } builder.bindLabel(resultLabel); } - + private class FinallyBlockGenerator { private final JetFinallySection finallyBlock; private Label startFinally = null; @@ -382,7 +426,6 @@ public class JetControlFlowProcessor { @Override public void visitTryExpression(@NotNull JetTryExpression expression) { - builder.read(expression); JetFinallySection finallyBlock = expression.getFinallyBlock(); final FinallyBlockGenerator finallyBlockGenerator = new FinallyBlockGenerator(finallyBlock); if (finallyBlock != null) { @@ -414,7 +457,6 @@ public class JetControlFlowProcessor { } generateInstructions(expression.getTryBlock(), inCondition); - Collection