Support functional expression in non-local returns

This commit is contained in:
Michael Bogdanov
2015-04-27 13:59:15 +03:00
parent 3a6e5ac78c
commit e0aa64b8d2
18 changed files with 210 additions and 81 deletions
@@ -94,8 +94,7 @@ import static org.jetbrains.kotlin.psi.PsiPackage.JetPsiFactory;
import static org.jetbrains.kotlin.resolve.BindingContext.*;
import static org.jetbrains.kotlin.resolve.BindingContextUtils.getNotNull;
import static org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure;
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.calls.callUtil.CallUtilPackage.getResolvedCall;
import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getResolvedCallWithAssert;
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getBuiltIns;
@@ -1845,13 +1844,18 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
@Nullable
private NonLocalReturnInfo getNonLocalReturnInfo(@NotNull CallableMemberDescriptor descriptor, @NotNull JetReturnExpression expression) {
//call inside lambda
if (DescriptorUtils.isFunctionLiteral(descriptor)) {
if (isFunctionLiteral(descriptor) || isFunctionExpression(descriptor)) {
if (expression.getLabelName() == null) {
//non labeled return couldn't be local in lambda
FunctionDescriptor containingFunction =
BindingContextUtils.getContainingFunctionSkipFunctionLiterals(descriptor, true).getFirst();
//ROOT_LABEL to prevent clashing with existing labels
return new NonLocalReturnInfo(typeMapper.mapReturnType(containingFunction), InlineCodegenUtil.ROOT_LABEL);
if (isFunctionLiteral(descriptor)) {
//non labeled return couldn't be local in lambda
FunctionDescriptor containingFunction =
BindingContextUtils.getContainingFunctionSkipFunctionLiterals(descriptor, false).getFirst();
//FIRST_FUN_LABEL to prevent clashing with existing labels
return new NonLocalReturnInfo(typeMapper.mapReturnType(containingFunction), InlineCodegenUtil.FIRST_FUN_LABEL);
} else {
//local
return null;
}
}
PsiElement element = bindingContext.get(LABEL_TARGET, expression.getTargetLabel());
@@ -35,8 +35,7 @@ import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass;
import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass;
import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackageFragmentProvider;
import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.kotlin.psi.JetFunctionLiteral;
import org.jetbrains.kotlin.psi.JetFunctionLiteralExpression;
import org.jetbrains.kotlin.psi.JetFunction;
import org.jetbrains.kotlin.psi.codeFragmentUtil.CodeFragmentUtilPackage;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
@@ -233,9 +232,8 @@ public class JvmCodegenUtil {
public static boolean isLambdaWhichWillBeInlined(@NotNull BindingContext bindingContext, @NotNull DeclarationDescriptor descriptor) {
PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
return declaration instanceof JetFunctionLiteral &&
declaration.getParent() instanceof JetFunctionLiteralExpression &&
InlineUtil.isInlineLambda((JetFunctionLiteralExpression) declaration.getParent(), bindingContext, false);
return InlineUtil.isFunctionalExpression(declaration) &&
InlineUtil.isInlineLambda((JetFunction)declaration, bindingContext, false);
}
@Nullable
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.codegen.inline;
import com.google.common.collect.ImmutableSet;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
@@ -34,7 +35,6 @@ import org.jetbrains.kotlin.load.kotlin.PackageClassUtils;
import org.jetbrains.kotlin.name.ClassId;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
@@ -55,10 +55,7 @@ import org.jetbrains.org.objectweb.asm.tree.LabelNode;
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.*;
import static org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags;
import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive;
@@ -269,33 +266,15 @@ public class InlineCodegen extends CallGenerator {
InlineResult result = inliner.doInline(adapter, remapper, true, LabelOwner.SKIP_ALL);
result.getReifiedTypeParametersUsages().mergeAll(reificationResult);
CallableMemberDescriptor descriptor = codegen.getContext().getContextDescriptor();
final Set<String> labels = getDeclarationLabels(DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor);
LabelOwner labelOwner = new LabelOwner() {
final CallableMemberDescriptor descriptor = codegen.getContext().getContextDescriptor();
@Override
public boolean isMyLabel(@NotNull String name) {
if (InlineCodegenUtil.ROOT_LABEL.equals(name)) {
return !isFunctionLiteral(descriptor);
}
//check function name if exists
if (descriptor.getName().asString().equals(name)) {
return true;
}
//check functional expression labels
if (isFunctionExpression(descriptor)) {
PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
if (element != null && element.getParent() instanceof JetLabeledExpression) {
String labelName = ((JetLabeledExpression) element.getParent()).getLabelName();
return name.equals(labelName);
}
}
return false;
return labels.contains(name);
}
};
List<MethodInliner.PointForExternalFinallyBlocks> infos = MethodInliner.processReturns(adapter, labelOwner, true, null);
generateAndInsertFinallyBlocks(adapter, infos, ((StackValue.Local)remapper.remap(parameters.totalSize() + 1).value).index);
@@ -549,23 +528,35 @@ public class InlineCodegen extends CallGenerator {
public void rememberClosure(JetExpression expression, Type type) {
JetExpression lambda = JetPsiUtil.deparenthesize(expression);
assert isInlinableParameterExpression(lambda) :"Couldn't find inline expression in " + expression.getText();
assert isInlinableParameterExpression(lambda) : "Couldn't find inline expression in " + expression.getText();
String labelNameIfPresent = null;
PsiElement parent = lambda.getParent();
if (parent instanceof JetLabeledExpression) {
labelNameIfPresent = ((JetLabeledExpression) parent).getLabelName();
}
if (lambda instanceof JetFunctionLiteralExpression) {
lambda = ((JetFunctionLiteralExpression) lambda).getFunctionLiteral();
}
LambdaInfo info = new LambdaInfo(lambda, typeMapper, labelNameIfPresent);
LambdaInfo info = new LambdaInfo(lambda, typeMapper);
ParameterInfo closureInfo = invocationParamBuilder.addNextParameter(type, true, null);
closureInfo.setLambda(info);
expressionMap.put(closureInfo.getIndex(), info);
}
@NotNull
protected static Set<String> getDeclarationLabels(@Nullable PsiElement lambdaOrFun, @NotNull DeclarationDescriptor descriptor) {
Set<String> result = new HashSet<String>();
if (lambdaOrFun != null) {
PsiElement parent = lambdaOrFun.getParent();
if (parent instanceof JetLabeledExpression) {
String labelName = ((JetLabeledExpression) parent).getLabelName();
assert labelName != null : "Labeled expression should have not nul label " + parent.getText();
result.add(labelName);
}
}
if (!isFunctionLiteral(descriptor)) {
if (!descriptor.getName().isSpecial()) {
result.add(descriptor.getName().asString());
}
result.add(InlineCodegenUtil.FIRST_FUN_LABEL);
}
return result;
}
private void putClosureParametersOnStack() {
for (LambdaInfo next : expressionMap.values()) {
activeLambda = next;
@@ -77,7 +77,7 @@ public class InlineCodegenUtil {
public static final String NON_LOCAL_RETURN = "$$$$$NON_LOCAL_RETURN$$$$$";
public static final String ROOT_LABEL = "$$$$$ROOT$$$$$";
public static final String FIRST_FUN_LABEL = "$$$$$ROOT$$$$$";
public static final String INLINE_MARKER_CLASS_NAME = "kotlin/jvm/internal/InlineMarker";
public static final String INLINE_MARKER_BEFORE_METHOD_NAME = "beforeInlineCall";
public static final String INLINE_MARKER_AFTER_METHOD_NAME = "afterInlineCall";
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.codegen.inline;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.AsmUtil;
import org.jetbrains.kotlin.codegen.StackValue;
import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
@@ -27,7 +26,9 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
import org.jetbrains.kotlin.psi.JetExpression;
import org.jetbrains.kotlin.psi.JetFunctionLiteralExpression;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode;
@@ -35,6 +36,7 @@ import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
@@ -44,8 +46,8 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner {
private final JetTypeMapper typeMapper;
@Nullable
public final String labelName;
@NotNull
public final Set<String> labels;
private final CalculatedClosure closure;
@@ -59,10 +61,11 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner {
private final Type closureClassType;
LambdaInfo(@NotNull JetExpression expression, @NotNull JetTypeMapper typeMapper, @Nullable String labelName) {
this.expression = expression;
LambdaInfo(@NotNull JetExpression expr, @NotNull JetTypeMapper typeMapper) {
this.expression = expr instanceof JetFunctionLiteralExpression ?
((JetFunctionLiteralExpression) expr).getFunctionLiteral() : expr;
this.typeMapper = typeMapper;
this.labelName = labelName;
BindingContext bindingContext = typeMapper.getBindingContext();
functionDescriptor = bindingContext.get(BindingContext.FUNCTION, expression);
assert functionDescriptor != null : "Function is not resolved to descriptor: " + expression.getText();
@@ -72,6 +75,9 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner {
closure = bindingContext.get(CLOSURE, classDescriptor);
assert closure != null : "Closure for lambda should be not null " + expression.getText();
labels = InlineCodegen.getDeclarationLabels(expr, functionDescriptor);
}
public SMAPAndMethodNode getNode() {
@@ -171,7 +177,7 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner {
@Override
public boolean isMyLabel(@NotNull String name) {
return name.equals(labelName);
return labels.contains(name);
}
}