refactoring: extracted methods

createValueParameterDescriptor, computeReturnType, computeUnsafeReturnType
This commit is contained in:
Svetlana Isakova
2012-12-25 20:25:36 +04:00
parent 122c2cbefb
commit b8507c0391
@@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.types.expressions;
import com.google.common.collect.Lists;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.*;
@@ -92,59 +93,20 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
@Override
public JetTypeInfo visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, ExpressionTypingContext context) {
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
JetBlockExpression bodyExpression = functionLiteral.getBodyExpression();
JetBlockExpression bodyExpression = expression.getFunctionLiteral().getBodyExpression();
if (bodyExpression == null) return null;
JetType expectedType = context.expectedType;
boolean functionTypeExpected = expectedType != NO_EXPECTED_TYPE && KotlinBuiltIns.getInstance().isFunctionType(expectedType);
SimpleFunctionDescriptorImpl functionDescriptor = createFunctionDescriptor(expression, context, functionTypeExpected);
List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters();
ReceiverParameterDescriptor receiverParameter = functionDescriptor.getReceiverParameter();
JetType receiver = DescriptorUtils.getReceiverParameterType(receiverParameter);
JetType returnType = NO_EXPECTED_TYPE;
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(context.scope, functionDescriptor, context.trace);
JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef();
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve function literal expression", expression);
JetType expectedReturnType = functionTypeExpected ? KotlinBuiltIns.getInstance().getReturnTypeFromFunctionType(expectedType) : null;
if (returnTypeRef != null) {
returnType = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, returnTypeRef, context.trace, true);
context.expressionTypingServices.checkFunctionReturnType(expression, context.replaceScope(functionInnerScope).
replaceExpectedType(returnType).replaceBindingTrace(temporaryTrace), temporaryTrace);
if (functionTypeExpected) {
if (!JetTypeChecker.INSTANCE.isSubtypeOf(expectedReturnType, returnType)) {
temporaryTrace.report(EXPECTED_RETURN_TYPE_MISMATCH.on(returnTypeRef, expectedReturnType));
}
}
}
else {
if (functionTypeExpected) {
returnType = expectedReturnType;
}
returnType = context.expressionTypingServices.getBlockReturnedType(functionInnerScope, bodyExpression, CoercionStrategy.COERCION_TO_UNIT,
context.replaceExpectedType(returnType).replaceBindingTrace(temporaryTrace), temporaryTrace).getType();
}
temporaryTrace.commit(new TraceEntryFilter() {
@Override
public boolean accept(@NotNull WritableSlice<?, ?> slice, Object key) {
return (slice != BindingContext.RESOLUTION_RESULTS_FOR_FUNCTION && slice != BindingContext.RESOLUTION_RESULTS_FOR_PROPERTY &&
slice != BindingContext.TRACE_DELTAS_CACHE);
}
}, true);
JetType safeReturnType = returnType == null ? ErrorUtils.createErrorType("<return type>") : returnType;
if (!functionLiteral.hasDeclaredReturnType() && functionTypeExpected) {
if (KotlinBuiltIns.getInstance().isUnit(expectedReturnType)) {
safeReturnType = KotlinBuiltIns.getInstance().getUnitType();
}
}
JetType safeReturnType = computeReturnType(expression, context, functionDescriptor, functionTypeExpected);
functionDescriptor.setReturnType(safeReturnType);
JetType receiver = DescriptorUtils.getReceiverParameterType(functionDescriptor.getReceiverParameter());
List<JetType> valueParametersTypes = DescriptorUtils.getValueParametersTypes(functionDescriptor.getValueParameters());
JetType resultType = KotlinBuiltIns.getInstance().getFunctionType(
Collections.<AnnotationDescriptor>emptyList(), receiver, DescriptorUtils.getValueParametersTypes(valueParameters), safeReturnType);
Collections.<AnnotationDescriptor>emptyList(), receiver, valueParametersTypes, safeReturnType);
if (expectedType != NO_EXPECTED_TYPE && KotlinBuiltIns.getInstance().isFunctionType(expectedType)) {
// all checks were done before
return JetTypeInfo.create(resultType, context.dataFlowInfo);
@@ -153,7 +115,7 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
}
@NotNull
private SimpleFunctionDescriptorImpl createFunctionDescriptor(
private static SimpleFunctionDescriptorImpl createFunctionDescriptor(
@NotNull JetFunctionLiteralExpression expression,
@NotNull ExpressionTypingContext context,
boolean functionTypeExpected
@@ -192,7 +154,7 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
}
@NotNull
private List<ValueParameterDescriptor> createValueParameterDescriptors(
private static List<ValueParameterDescriptor> createValueParameterDescriptors(
@NotNull ExpressionTypingContext context,
@NotNull JetFunctionLiteral functionLiteral,
@NotNull FunctionDescriptorImpl functionDescriptor,
@@ -222,41 +184,111 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(EXPECTED_PARAMETERS_NUMBER_MISMATCH.on(functionLiteral, expectedParameterTypes.size(), expectedParameterTypes));
}
for (int i = 0; i < declaredValueParameters.size(); i++) {
JetParameter declaredParameter = declaredValueParameters.get(i);
JetTypeReference typeReference = declaredParameter.getTypeReference();
JetType expectedType;
if (expectedValueParameters != null && i < expectedValueParameters.size()) {
expectedType = expectedValueParameters.get(i).getType();
}
else {
expectedType = null;
}
JetType type;
if (typeReference != null) {
type = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, typeReference, context.trace, true);
if (expectedType != null) {
if (!JetTypeChecker.INSTANCE.isSubtypeOf(type, expectedType)) {
context.trace.report(EXPECTED_PARAMETER_TYPE_MISMATCH.on(declaredParameter, expectedType));
}
}
}
else {
if (expectedType == null || expectedType == CallResolverUtil.DONT_CARE || expectedType == CallResolverUtil.CANT_INFER) {
context.trace.report(CANNOT_INFER_PARAMETER_TYPE.on(declaredParameter));
}
if (expectedType != null) {
type = expectedType;
}
else {
type = ErrorUtils.createErrorType("Cannot be inferred");
}
}
ValueParameterDescriptor valueParameterDescriptor = context.expressionTypingServices.getDescriptorResolver().resolveValueParameterDescriptor(
context.scope, functionDescriptor, declaredParameter, i, type, context.trace);
ValueParameterDescriptor valueParameterDescriptor = createValueParameterDescriptor(
context, functionDescriptor, declaredValueParameters, expectedValueParameters, i);
valueParameterDescriptors.add(valueParameterDescriptor);
}
}
return valueParameterDescriptors;
}
@NotNull
private static ValueParameterDescriptor createValueParameterDescriptor(
@NotNull ExpressionTypingContext context,
@NotNull FunctionDescriptorImpl functionDescriptor,
@NotNull List<JetParameter> declaredValueParameters,
@Nullable List<ValueParameterDescriptor> expectedValueParameters,
int index
) {
JetParameter declaredParameter = declaredValueParameters.get(index);
JetTypeReference typeReference = declaredParameter.getTypeReference();
JetType expectedType;
if (expectedValueParameters != null && index < expectedValueParameters.size()) {
expectedType = expectedValueParameters.get(index).getType();
}
else {
expectedType = null;
}
JetType type;
if (typeReference != null) {
type = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, typeReference, context.trace, true);
if (expectedType != null) {
if (!JetTypeChecker.INSTANCE.isSubtypeOf(type, expectedType)) {
context.trace.report(EXPECTED_PARAMETER_TYPE_MISMATCH.on(declaredParameter, expectedType));
}
}
}
else {
if (expectedType == null || expectedType == CallResolverUtil.DONT_CARE || expectedType == CallResolverUtil.CANT_INFER) {
context.trace.report(CANNOT_INFER_PARAMETER_TYPE.on(declaredParameter));
}
if (expectedType != null) {
type = expectedType;
}
else {
type = ErrorUtils.createErrorType("Cannot be inferred");
}
}
return context.expressionTypingServices.getDescriptorResolver().resolveValueParameterDescriptor(
context.scope, functionDescriptor, declaredParameter, index, type, context.trace);
}
@NotNull
private static JetType computeReturnType(
@NotNull JetFunctionLiteralExpression expression,
@NotNull ExpressionTypingContext context,
@NotNull SimpleFunctionDescriptorImpl functionDescriptor,
boolean functionTypeExpected
) {
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve function literal expression", expression);
JetType expectedReturnType = functionTypeExpected ? KotlinBuiltIns.getInstance().getReturnTypeFromFunctionType(context.expectedType) : null;
JetType returnType = computeUnsafeReturnType(expression, context, functionDescriptor, temporaryTrace, expectedReturnType);
temporaryTrace.commit(new TraceEntryFilter() {
@Override
public boolean accept(@NotNull WritableSlice<?, ?> slice, Object key) {
return (slice != BindingContext.RESOLUTION_RESULTS_FOR_FUNCTION && slice != BindingContext.RESOLUTION_RESULTS_FOR_PROPERTY &&
slice != BindingContext.TRACE_DELTAS_CACHE);
}
}, true);
if (!expression.getFunctionLiteral().hasDeclaredReturnType() && functionTypeExpected) {
if (KotlinBuiltIns.getInstance().isUnit(expectedReturnType)) {
return KotlinBuiltIns.getInstance().getUnitType();
}
}
return returnType == null ? ErrorUtils.createErrorType("<return type>") : returnType;
}
@Nullable
private static JetType computeUnsafeReturnType(
@NotNull JetFunctionLiteralExpression expression,
@NotNull ExpressionTypingContext context,
@NotNull SimpleFunctionDescriptorImpl functionDescriptor,
@NotNull TemporaryBindingTrace temporaryTrace,
@Nullable JetType expectedReturnType
) {
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
JetBlockExpression bodyExpression = functionLiteral.getBodyExpression();
assert bodyExpression != null;
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(context.scope, functionDescriptor, context.trace);
JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef();
if (returnTypeRef != null) {
JetType returnType = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, returnTypeRef, context.trace, true);
context.expressionTypingServices.checkFunctionReturnType(expression, context.replaceScope(functionInnerScope).
replaceExpectedType(returnType).replaceBindingTrace(temporaryTrace), temporaryTrace);
if (expectedReturnType != null) {
if (!JetTypeChecker.INSTANCE.isSubtypeOf(expectedReturnType, returnType)) {
temporaryTrace.report(EXPECTED_RETURN_TYPE_MISMATCH.on(returnTypeRef, expectedReturnType));
}
}
return returnType;
}
ExpressionTypingContext newContext = context.replaceExpectedType(expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE)
.replaceBindingTrace(temporaryTrace);
return context.expressionTypingServices.getBlockReturnedType(functionInnerScope, bodyExpression, CoercionStrategy.COERCION_TO_UNIT,
newContext, temporaryTrace).getType();
}
}