Refactor: get rid of static ConstantExpressionEvaluator.evaluate function

Move ArgumentTypeResolver.getLastElementDeparenthesized to JetPsiUtil
This commit is contained in:
Pavel V. Talanov
2015-07-23 16:48:19 +03:00
parent 2b9fc5268e
commit 6698b3b070
7 changed files with 71 additions and 62 deletions
@@ -41,6 +41,8 @@ import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.name.SpecialNames;
import org.jetbrains.kotlin.parsing.JetExpressionParsing;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
import org.jetbrains.kotlin.resolve.ResolvePackage;
import org.jetbrains.kotlin.resolve.StatementFilter;
import org.jetbrains.kotlin.types.expressions.OperatorConventions;
import java.util.Collection;
@@ -875,4 +877,24 @@ public class JetPsiUtil {
return false;
}
@Nullable
public static JetExpression getLastElementDeparenthesized(
@Nullable JetExpression expression,
@NotNull StatementFilter statementFilter
) {
JetExpression deparenthesizedExpression = JetPsiUtil.deparenthesize(expression, false);
if (deparenthesizedExpression instanceof JetBlockExpression) {
JetBlockExpression blockExpression = (JetBlockExpression) deparenthesizedExpression;
// todo
// This case is a temporary hack for 'if' branches.
// The right way to implement this logic is to interpret 'if' branches as function literals with explicitly-typed signatures
// (no arguments and no receiver) and therefore analyze them straight away (not in the 'complete' phase).
JetExpression lastStatementInABlock = ResolvePackage.getLastStatementInABlock(statementFilter, blockExpression);
if (lastStatementInABlock != null) {
return getLastElementDeparenthesized(lastStatementInABlock, statementFilter);
}
}
return deparenthesizedExpression;
}
}
@@ -53,6 +53,7 @@ import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPac
import java.util.Collections;
import java.util.List;
import static org.jetbrains.kotlin.psi.JetPsiUtil.getLastElementDeparenthesized;
import static org.jetbrains.kotlin.resolve.BindingContextUtils.getRecordedTypeInfo;
import static org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS;
import static org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS;
@@ -68,19 +69,22 @@ public class ArgumentTypeResolver {
@NotNull private final ExpressionTypingServices expressionTypingServices;
@NotNull private final KotlinBuiltIns builtIns;
@NotNull private final ReflectionTypes reflectionTypes;
@NotNull private final ConstantExpressionEvaluator constantExpressionEvaluator;
public ArgumentTypeResolver(
@NotNull TypeResolver typeResolver,
@NotNull CallResolver callResolver,
@NotNull ExpressionTypingServices expressionTypingServices,
@NotNull KotlinBuiltIns builtIns,
@NotNull ReflectionTypes reflectionTypes
@NotNull ReflectionTypes reflectionTypes,
@NotNull ConstantExpressionEvaluator constantExpressionEvaluator
) {
this.typeResolver = typeResolver;
this.callResolver = callResolver;
this.expressionTypingServices = expressionTypingServices;
this.builtIns = builtIns;
this.reflectionTypes = reflectionTypes;
this.constantExpressionEvaluator = constantExpressionEvaluator;
}
public static boolean isSubtypeOfForArgumentType(
@@ -171,26 +175,6 @@ public class ArgumentTypeResolver {
return null;
}
@Nullable
public static JetExpression getLastElementDeparenthesized(
@Nullable JetExpression expression,
@NotNull StatementFilter statementFilter
) {
JetExpression deparenthesizedExpression = JetPsiUtil.deparenthesize(expression, false);
if (deparenthesizedExpression instanceof JetBlockExpression) {
JetBlockExpression blockExpression = (JetBlockExpression) deparenthesizedExpression;
// todo
// This case is a temporary hack for 'if' branches.
// The right way to implement this logic is to interpret 'if' branches as function literals with explicitly-typed signatures
// (no arguments and no receiver) and therefore analyze them straight away (not in the 'complete' phase).
JetExpression lastStatementInABlock = ResolvePackage.getLastStatementInABlock(statementFilter, blockExpression);
if (lastStatementInABlock != null) {
return getLastElementDeparenthesized(lastStatementInABlock, statementFilter);
}
}
return deparenthesizedExpression;
}
@Nullable
public static JetCallableReferenceExpression getCallableReferenceExpressionIfAny(
@NotNull JetExpression expression,
@@ -356,7 +340,7 @@ public class ArgumentTypeResolver {
}
@Nullable
public static JetType updateResultArgumentTypeIfNotDenotable(
public JetType updateResultArgumentTypeIfNotDenotable(
@NotNull ResolutionContext context,
@NotNull JetExpression expression
) {
@@ -365,30 +349,10 @@ public class ArgumentTypeResolver {
if (type.getConstructor() instanceof IntegerValueTypeConstructor) {
IntegerValueTypeConstructor constructor = (IntegerValueTypeConstructor) type.getConstructor();
JetType primitiveType = TypeUtils.getPrimitiveNumberType(constructor, context.expectedType);
updateNumberType(primitiveType, expression, context.statementFilter, context.trace);
constantExpressionEvaluator.updateNumberType(primitiveType, expression, context.statementFilter, context.trace);
return primitiveType;
}
}
return type;
}
public static void updateNumberType(
@NotNull JetType numberType,
@Nullable JetExpression expression,
@NotNull StatementFilter statementFilter,
@NotNull BindingTrace trace
) {
if (expression == null) return;
BindingContextUtils.updateRecordedType(numberType, expression, trace, false);
if (!(expression instanceof JetConstantExpression)) {
JetExpression deparenthesized = getLastElementDeparenthesized(expression, statementFilter);
if (deparenthesized != expression) {
updateNumberType(numberType, deparenthesized, statementFilter, trace);
}
return;
}
ConstantExpressionEvaluator.evaluate(expression, trace, numberType);
}
}
@@ -32,7 +32,9 @@ import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.*
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.EXPECTED_TYPE_POSITION
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.FROM_COMPLETER
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.TYPE_BOUND_POSITION
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
@@ -235,7 +237,7 @@ public class CallCompleter(
if (valueArgument.isExternal()) return
val expression = valueArgument.getArgumentExpression() ?: return
val deparenthesized = ArgumentTypeResolver.getLastElementDeparenthesized(expression, context.statementFilter) ?: return
val deparenthesized = JetPsiUtil.getLastElementDeparenthesized(expression, context.statementFilter) ?: return
val recordedType = expression.let { context.trace.getType(it) }
var updatedType: JetType? = recordedType
@@ -249,7 +251,7 @@ public class CallCompleter(
// For the cases like 'foo(1)' the type of '1' depends on expected type (it can be Int, Byte, etc.),
// so while the expected type is not known, it's IntegerValueType(1), and should be updated when the expected type is known.
if (recordedType != null && !recordedType.getConstructor().isDenotable()) {
updatedType = ArgumentTypeResolver.updateResultArgumentTypeIfNotDenotable(context, expression)
updatedType = argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(context, expression)
}
updatedType = updateRecordedTypeForArgument(updatedType, recordedType, expression, context.trace)
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.FunctionDescriptorUtil
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver.getLastElementDeparenthesized
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.*
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS
@@ -34,10 +33,8 @@ import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.RECEIVER_POSITION
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.EXPECTED_TYPE_POSITION
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.INCOMPLETE_TYPE_INFERENCE
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.OTHER_ERROR
@@ -184,7 +181,7 @@ class GenericCandidateResolver(
argumentExpression: JetExpression?,
context: ResolutionContext<*>
): JetType? {
val deparenthesizedArgument = getLastElementDeparenthesized(argumentExpression, context.statementFilter)
val deparenthesizedArgument = JetPsiUtil.getLastElementDeparenthesized(argumentExpression, context.statementFilter)
if (deparenthesizedArgument == null || type == null) return type
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(deparenthesizedArgument, type, context)
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
@@ -48,6 +47,25 @@ public class ConstantExpressionEvaluator(
internal val constantValueFactory: ConstantValueFactory,
internal val builtIns: KotlinBuiltIns
) {
public fun updateNumberType(
numberType: JetType,
expression: JetExpression?,
statementFilter: StatementFilter,
trace: BindingTrace
) {
if (expression == null) return
BindingContextUtils.updateRecordedType(numberType, expression, trace, false)
if (expression !is JetConstantExpression) {
val deparenthesized = JetPsiUtil.getLastElementDeparenthesized(expression, statementFilter)
if (deparenthesized !== expression) {
updateNumberType(numberType, deparenthesized, statementFilter, trace)
}
return
}
evaluateExpression(expression, trace, numberType)
}
internal fun resolveAnnotationArguments(
resolvedCall: ResolvedCall<*>,
@@ -160,10 +178,10 @@ public class ConstantExpressionEvaluator(
val constants = ArrayList<CompileTimeConstant<*>>()
for (argument in resolvedValueArgument.getArguments()) {
val argumentExpression = argument.getArgumentExpression() ?: continue
val constant = ConstantExpressionEvaluator.evaluate(argumentExpression, trace, expectedType)
val constant = evaluateExpression(argumentExpression, trace, expectedType)
if (constant is IntegerValueTypeConstant) {
val defaultType = constant.getType(expectedType)
ArgumentTypeResolver.updateNumberType(defaultType, argumentExpression, StatementFilter.NONE, trace)
updateNumberType(defaultType, argumentExpression, StatementFilter.NONE, trace)
}
if (constant != null) {
constants.add(constant)
@@ -184,17 +202,15 @@ public class ConstantExpressionEvaluator(
}
companion object {
platformStatic public fun evaluate(expression: JetExpression, trace: BindingTrace, expectedType: JetType? = TypeUtils.NO_EXPECTED_TYPE): CompileTimeConstant<*>? {
val builtIns = KotlinBuiltIns.getInstance()
return ConstantExpressionEvaluator(ConstantValueFactory(builtIns), builtIns).evaluateExpression(expression, trace, expectedType)
}
platformStatic public fun evaluateToConstantValue(
expression: JetExpression,
trace: BindingTrace,
expectedType: JetType
): ConstantValue<*>? {
return evaluate(expression, trace, expectedType)?.toConstantValue(expectedType)
val builtIns = KotlinBuiltIns.getInstance()
return ConstantExpressionEvaluator(ConstantValueFactory(builtIns), builtIns).
evaluateExpression(expression, trace, expectedType)?.
toConstantValue(expectedType)
}
platformStatic public fun getConstant(expression: JetExpression, bindingContext: BindingContext): CompileTimeConstant<*>? {
@@ -50,9 +50,14 @@ import static org.jetbrains.kotlin.types.TypeUtils.*;
public class DataFlowAnalyzer {
private final Iterable<? extends AdditionalTypeChecker> additionalTypeCheckers;
private final ConstantExpressionEvaluator constantExpressionEvaluator;
public DataFlowAnalyzer(@NotNull Iterable<? extends AdditionalTypeChecker> additionalTypeCheckers) {
public DataFlowAnalyzer(
@NotNull Iterable<? extends AdditionalTypeChecker> additionalTypeCheckers,
@NotNull ConstantExpressionEvaluator constantExpressionEvaluator
) {
this.additionalTypeCheckers = additionalTypeCheckers;
this.constantExpressionEvaluator = constantExpressionEvaluator;
}
@NotNull
@@ -293,7 +298,7 @@ public class DataFlowAnalyzer {
IntegerValueTypeConstant integerValueTypeConstant = (IntegerValueTypeConstant) value;
if (context.contextDependency == INDEPENDENT) {
expressionType = integerValueTypeConstant.getType(context.expectedType);
ArgumentTypeResolver.updateNumberType(expressionType, expression, context.statementFilter, context.trace);
constantExpressionEvaluator.updateNumberType(expressionType, expression, context.statementFilter, context.trace);
}
else {
expressionType = integerValueTypeConstant.getUnknownIntegerType();
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.resolve.constants.evaluate
import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.psi.JetProperty
import org.jetbrains.kotlin.resolve.BindingContext
@@ -24,6 +25,7 @@ import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.annotation.AbstractAnnotationDescriptorResolveTest
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
import org.jetbrains.kotlin.resolve.constants.ConstantValueFactory
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.JetTestUtils
@@ -64,7 +66,8 @@ public abstract class AbstractEvaluateExpressionTest : AbstractAnnotationDescrip
private fun evaluateInitializer(context: BindingContext, property: VariableDescriptor): CompileTimeConstant<*>? {
val propertyDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(property) as JetProperty
val compileTimeConstant = ConstantExpressionEvaluator.evaluate(
val builtIns = KotlinBuiltIns.getInstance()
val compileTimeConstant = ConstantExpressionEvaluator(ConstantValueFactory(builtIns), builtIns).evaluateExpression(
propertyDeclaration.getInitializer()!!,
DelegatingBindingTrace(context, "trace for evaluating compile time constant"),
property.getType()