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.google.common.collect.Lists;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
@@ -92,59 +93,20 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JetTypeInfo visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, ExpressionTypingContext context) {
|
public JetTypeInfo visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, ExpressionTypingContext context) {
|
||||||
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
|
JetBlockExpression bodyExpression = expression.getFunctionLiteral().getBodyExpression();
|
||||||
JetBlockExpression bodyExpression = functionLiteral.getBodyExpression();
|
|
||||||
if (bodyExpression == null) return null;
|
if (bodyExpression == null) return null;
|
||||||
|
|
||||||
JetType expectedType = context.expectedType;
|
JetType expectedType = context.expectedType;
|
||||||
boolean functionTypeExpected = expectedType != NO_EXPECTED_TYPE && KotlinBuiltIns.getInstance().isFunctionType(expectedType);
|
boolean functionTypeExpected = expectedType != NO_EXPECTED_TYPE && KotlinBuiltIns.getInstance().isFunctionType(expectedType);
|
||||||
|
|
||||||
SimpleFunctionDescriptorImpl functionDescriptor = createFunctionDescriptor(expression, context, functionTypeExpected);
|
SimpleFunctionDescriptorImpl functionDescriptor = createFunctionDescriptor(expression, context, functionTypeExpected);
|
||||||
|
JetType safeReturnType = computeReturnType(expression, context, functionDescriptor, 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
functionDescriptor.setReturnType(safeReturnType);
|
functionDescriptor.setReturnType(safeReturnType);
|
||||||
|
|
||||||
|
JetType receiver = DescriptorUtils.getReceiverParameterType(functionDescriptor.getReceiverParameter());
|
||||||
|
List<JetType> valueParametersTypes = DescriptorUtils.getValueParametersTypes(functionDescriptor.getValueParameters());
|
||||||
JetType resultType = KotlinBuiltIns.getInstance().getFunctionType(
|
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)) {
|
if (expectedType != NO_EXPECTED_TYPE && KotlinBuiltIns.getInstance().isFunctionType(expectedType)) {
|
||||||
// all checks were done before
|
// all checks were done before
|
||||||
return JetTypeInfo.create(resultType, context.dataFlowInfo);
|
return JetTypeInfo.create(resultType, context.dataFlowInfo);
|
||||||
@@ -153,7 +115,7 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private SimpleFunctionDescriptorImpl createFunctionDescriptor(
|
private static SimpleFunctionDescriptorImpl createFunctionDescriptor(
|
||||||
@NotNull JetFunctionLiteralExpression expression,
|
@NotNull JetFunctionLiteralExpression expression,
|
||||||
@NotNull ExpressionTypingContext context,
|
@NotNull ExpressionTypingContext context,
|
||||||
boolean functionTypeExpected
|
boolean functionTypeExpected
|
||||||
@@ -192,7 +154,7 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private List<ValueParameterDescriptor> createValueParameterDescriptors(
|
private static List<ValueParameterDescriptor> createValueParameterDescriptors(
|
||||||
@NotNull ExpressionTypingContext context,
|
@NotNull ExpressionTypingContext context,
|
||||||
@NotNull JetFunctionLiteral functionLiteral,
|
@NotNull JetFunctionLiteral functionLiteral,
|
||||||
@NotNull FunctionDescriptorImpl functionDescriptor,
|
@NotNull FunctionDescriptorImpl functionDescriptor,
|
||||||
@@ -222,41 +184,111 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
context.trace.report(EXPECTED_PARAMETERS_NUMBER_MISMATCH.on(functionLiteral, expectedParameterTypes.size(), expectedParameterTypes));
|
context.trace.report(EXPECTED_PARAMETERS_NUMBER_MISMATCH.on(functionLiteral, expectedParameterTypes.size(), expectedParameterTypes));
|
||||||
}
|
}
|
||||||
for (int i = 0; i < declaredValueParameters.size(); i++) {
|
for (int i = 0; i < declaredValueParameters.size(); i++) {
|
||||||
JetParameter declaredParameter = declaredValueParameters.get(i);
|
ValueParameterDescriptor valueParameterDescriptor = createValueParameterDescriptor(
|
||||||
JetTypeReference typeReference = declaredParameter.getTypeReference();
|
context, functionDescriptor, declaredValueParameters, expectedValueParameters, i);
|
||||||
|
|
||||||
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);
|
|
||||||
valueParameterDescriptors.add(valueParameterDescriptor);
|
valueParameterDescriptors.add(valueParameterDescriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return valueParameterDescriptors;
|
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