refactoring: extracted methods
createValueParameterDescriptor, computeReturnType, computeUnsafeReturnType
This commit is contained in:
+110
-78
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user