Merge InlineDescriptorUtils to InlineUtil

This commit is contained in:
Alexander Udalov
2015-04-15 22:47:30 +03:00
parent 16e6bc347f
commit ccae0311c3
6 changed files with 107 additions and 126 deletions
@@ -41,8 +41,8 @@ import org.jetbrains.kotlin.psi.codeFragmentUtil.CodeFragmentUtilPackage;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.InlineDescriptorUtils;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor;
import org.jetbrains.kotlin.types.JetType;
@@ -235,7 +235,7 @@ public class JvmCodegenUtil {
PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
return declaration instanceof JetFunctionLiteral &&
declaration.getParent() instanceof JetFunctionLiteralExpression &&
InlineDescriptorUtils.isInlineLambda((JetFunctionLiteralExpression) declaration.getParent(), bindingContext, false);
InlineUtil.isInlineLambda((JetFunctionLiteralExpression) declaration.getParent(), bindingContext, false);
}
@Nullable
@@ -1,109 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMapping;
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
public class InlineDescriptorUtils {
public static boolean checkNonLocalReturnUsage(@NotNull DeclarationDescriptor fromFunction, @NotNull JetExpression startExpression, @NotNull BindingTrace trace) {
PsiElement containingFunction = PsiTreeUtil.getParentOfType(startExpression, JetClassOrObject.class, JetDeclarationWithBody.class);
if (containingFunction == null) {
return false;
}
DeclarationDescriptor containingFunctionDescriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, containingFunction);
if (containingFunctionDescriptor == null) {
return false;
}
BindingContext bindingContext = trace.getBindingContext();
while (containingFunction instanceof JetFunctionLiteral && fromFunction != containingFunctionDescriptor) {
//JetFunctionLiteralExpression
containingFunction = containingFunction.getParent();
if (!isInlineLambda((JetFunctionLiteralExpression) containingFunction, bindingContext, true)) {
return false;
}
containingFunctionDescriptor = getContainingClassOrFunctionDescriptor(containingFunctionDescriptor, true);
containingFunction = containingFunctionDescriptor != null
? DescriptorToSourceUtils.descriptorToDeclaration(containingFunctionDescriptor)
: null;
}
return fromFunction == containingFunctionDescriptor;
}
public static boolean isInlineLambda(
@NotNull JetFunctionLiteralExpression lambdaExpression,
@NotNull BindingContext bindingContext,
boolean checkNonLocalReturn
) {
JetExpression call = JetPsiUtil.getParentCallIfPresent(lambdaExpression);
if (call != null) {
ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(call, bindingContext);
if (resolvedCall != null && InlineUtil.isInline(resolvedCall.getResultingDescriptor())) {
ValueArgument argument = CallUtilPackage.getValueArgumentForExpression(resolvedCall.getCall(), lambdaExpression);
if (argument != null) {
ArgumentMapping mapping = resolvedCall.getArgumentMapping(argument);
if (mapping instanceof ArgumentMatch) {
ValueParameterDescriptor parameter = ((ArgumentMatch) mapping).getValueParameter();
if (InlineUtil.isInlineLambdaParameter(parameter)) {
return !checkNonLocalReturn || allowsNonLocalReturns(parameter);
}
}
}
}
}
return false;
}
@Nullable
public static DeclarationDescriptor getContainingClassOrFunctionDescriptor(@NotNull DeclarationDescriptor descriptor, boolean strict) {
DeclarationDescriptor currentDescriptor = strict ? descriptor.getContainingDeclaration() : descriptor;
while (currentDescriptor != null) {
if (currentDescriptor instanceof FunctionDescriptor || currentDescriptor instanceof ClassDescriptor) {
return currentDescriptor;
}
currentDescriptor = currentDescriptor.getContainingDeclaration();
}
return null;
}
public static boolean allowsNonLocalReturns(@NotNull CallableDescriptor lambdaDescriptor) {
if (lambdaDescriptor instanceof ValueParameterDescriptor) {
if (InlineUtil.hasOnlyLocalReturn((ValueParameterDescriptor) lambdaDescriptor)) {
//annotated
return false;
}
}
return true;
}
}
@@ -43,9 +43,9 @@ import java.util.Set;
import static org.jetbrains.kotlin.diagnostics.Errors.NON_LOCAL_RETURN_NOT_ALLOWED;
import static org.jetbrains.kotlin.diagnostics.Errors.USAGE_IS_NOT_INLINABLE;
import static org.jetbrains.kotlin.resolve.InlineDescriptorUtils.allowsNonLocalReturns;
import static org.jetbrains.kotlin.resolve.InlineDescriptorUtils.checkNonLocalReturnUsage;
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getIsEffectivelyPublicApi;
import static org.jetbrains.kotlin.resolve.inline.InlineUtil.allowsNonLocalReturns;
import static org.jetbrains.kotlin.resolve.inline.InlineUtil.checkNonLocalReturnUsage;
class InlineChecker implements CallChecker {
private final SimpleFunctionDescriptor descriptor;
@@ -25,13 +25,13 @@ import org.jetbrains.kotlin.psi.psiUtil.getTextWithLocation
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContext.CALL
import org.jetbrains.kotlin.resolve.BindingContext.RESOLVED_CALL
import org.jetbrains.kotlin.resolve.InlineDescriptorUtils
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatchStatus
import org.jetbrains.kotlin.resolve.calls.model.ArgumentUnmapped
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.utils.sure
// resolved call
@@ -184,5 +184,5 @@ public fun JetFunctionLiteral.isInlined(bindingContext: BindingContext): Boolean
val parent = this.getParent()
assert(parent is JetFunctionLiteralExpression) { "parent of JetFunctionLiteral is " + parent }
return InlineDescriptorUtils.isInlineLambda(parent as JetFunctionLiteralExpression, bindingContext, false)
}
return InlineUtil.isInlineLambda(parent as JetFunctionLiteralExpression, bindingContext, false)
}
@@ -16,15 +16,22 @@
package org.jetbrains.kotlin.resolve.inline;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor;
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMapping;
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.constants.ArrayValue;
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
import org.jetbrains.kotlin.resolve.constants.EnumValue;
@@ -83,4 +90,85 @@ public class InlineUtil {
return false;
}
public static boolean checkNonLocalReturnUsage(
@NotNull DeclarationDescriptor fromFunction,
@NotNull JetExpression startExpression,
@NotNull BindingTrace trace
) {
PsiElement containingFunction = PsiTreeUtil.getParentOfType(startExpression, JetClassOrObject.class, JetDeclarationWithBody.class);
if (containingFunction == null) {
return false;
}
DeclarationDescriptor containingFunctionDescriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, containingFunction);
if (containingFunctionDescriptor == null) {
return false;
}
BindingContext bindingContext = trace.getBindingContext();
while (containingFunction instanceof JetFunctionLiteral && fromFunction != containingFunctionDescriptor) {
//JetFunctionLiteralExpression
containingFunction = containingFunction.getParent();
if (!isInlineLambda((JetFunctionLiteralExpression) containingFunction, bindingContext, true)) {
return false;
}
containingFunctionDescriptor = getContainingClassOrFunctionDescriptor(containingFunctionDescriptor, true);
containingFunction = containingFunctionDescriptor != null
? DescriptorToSourceUtils.descriptorToDeclaration(containingFunctionDescriptor)
: null;
}
return fromFunction == containingFunctionDescriptor;
}
public static boolean isInlineLambda(
@NotNull JetFunctionLiteralExpression lambdaExpression,
@NotNull BindingContext bindingContext,
boolean checkNonLocalReturn
) {
JetExpression call = JetPsiUtil.getParentCallIfPresent(lambdaExpression);
if (call != null) {
ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(call, bindingContext);
if (resolvedCall != null && isInline(resolvedCall.getResultingDescriptor())) {
ValueArgument argument = CallUtilPackage.getValueArgumentForExpression(resolvedCall.getCall(), lambdaExpression);
if (argument != null) {
ArgumentMapping mapping = resolvedCall.getArgumentMapping(argument);
if (mapping instanceof ArgumentMatch) {
ValueParameterDescriptor parameter = ((ArgumentMatch) mapping).getValueParameter();
if (isInlineLambdaParameter(parameter)) {
return !checkNonLocalReturn || allowsNonLocalReturns(parameter);
}
}
}
}
}
return false;
}
@Nullable
public static DeclarationDescriptor getContainingClassOrFunctionDescriptor(@NotNull DeclarationDescriptor descriptor, boolean strict) {
DeclarationDescriptor current = strict ? descriptor.getContainingDeclaration() : descriptor;
while (current != null) {
if (current instanceof FunctionDescriptor || current instanceof ClassDescriptor) {
return current;
}
current = current.getContainingDeclaration();
}
return null;
}
public static boolean allowsNonLocalReturns(@NotNull CallableDescriptor lambda) {
if (lambda instanceof ValueParameterDescriptor) {
if (hasOnlyLocalReturn((ValueParameterDescriptor) lambda)) {
//annotated
return false;
}
}
return true;
}
}
@@ -28,10 +28,14 @@ import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingContextUtils;
import org.jetbrains.kotlin.resolve.DescriptorResolver;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
import org.jetbrains.kotlin.resolve.scopes.JetScope;
import org.jetbrains.kotlin.resolve.scopes.WritableScope;
import org.jetbrains.kotlin.resolve.scopes.WritableScopeImpl;
@@ -48,9 +52,7 @@ import static org.jetbrains.kotlin.diagnostics.Errors.*;
import static org.jetbrains.kotlin.psi.PsiPackage.JetPsiFactory;
import static org.jetbrains.kotlin.resolve.BindingContext.*;
import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT;
import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
import static org.jetbrains.kotlin.types.TypeUtils.isDontCarePlaceholder;
import static org.jetbrains.kotlin.types.TypeUtils.noExpectedType;
import static org.jetbrains.kotlin.types.TypeUtils.*;
import static org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.createCallForSpecialConstruction;
import static org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.createDataFlowInfoForArgumentsForIfCall;
import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.*;
@@ -496,7 +498,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
FunctionDescriptor containingFunctionDescriptor = containingFunInfo.getFirst();
if (containingFunctionDescriptor != null) {
if (!InlineDescriptorUtils.checkNonLocalReturnUsage(containingFunctionDescriptor, expression, context.trace) ||
if (!InlineUtil.checkNonLocalReturnUsage(containingFunctionDescriptor, expression, context.trace) ||
isClassInitializer(containingFunInfo)) {
// Unqualified, in a function literal
context.trace.report(RETURN_NOT_ALLOWED.on(expression));
@@ -515,7 +517,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
SimpleFunctionDescriptor functionDescriptor = context.trace.get(FUNCTION, labelTargetElement);
if (functionDescriptor != null) {
expectedType = getFunctionExpectedReturnType(functionDescriptor, labelTargetElement, context);
if (!InlineDescriptorUtils.checkNonLocalReturnUsage(functionDescriptor, expression, context.trace)) {
if (!InlineUtil.checkNonLocalReturnUsage(functionDescriptor, expression, context.trace)) {
// Qualified, non-local
context.trace.report(RETURN_NOT_ALLOWED.on(expression));
resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE);