Convert ClosureExpressionsTypingVisitor to kotlin

This commit is contained in:
Stanislav Erokhin
2015-02-24 19:19:15 +03:00
parent ee4892c99f
commit 779c6deb34
@@ -14,418 +14,341 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.types.expressions; package org.jetbrains.kotlin.types.expressions
import com.google.common.collect.Lists; import com.google.common.collect.Lists
import com.intellij.psi.PsiElement; import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import com.intellij.util.Function; import org.jetbrains.kotlin.descriptors.*
import com.intellij.util.containers.ContainerUtil; import org.jetbrains.kotlin.descriptors.annotations.Annotations
import kotlin.Function1; import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
import org.jetbrains.kotlin.descriptors.annotations.Annotations; import org.jetbrains.kotlin.diagnostics.Errors.*
import org.jetbrains.kotlin.descriptors.impl.*; import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils; import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.BindingContext.AUTO_CREATED_IT
import org.jetbrains.kotlin.resolve.*; import org.jetbrains.kotlin.resolve.BindingContext.EXPECTED_RETURN_TYPE
import org.jetbrains.kotlin.resolve.scopes.JetScope; import org.jetbrains.kotlin.resolve.BindingContext.EXPRESSION_TYPE
import org.jetbrains.kotlin.resolve.scopes.WritableScope; import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.types.*; import org.jetbrains.kotlin.resolve.scopes.WritableScope
import org.jetbrains.kotlin.types.checker.JetTypeChecker; import org.jetbrains.kotlin.resolve.source.toSourceElement
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.TypeUtils.CANT_INFER_LAMBDA_PARAM_TYPE
import org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE
import org.jetbrains.kotlin.types.TypeUtils.noExpectedType
import org.jetbrains.kotlin.types.checker.JetTypeChecker
import org.jetbrains.kotlin.types.expressions.CoercionStrategy.COERCION_TO_UNIT
import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.Collection; public class ClosureExpressionsTypingVisitor protected(facade: ExpressionTypingInternals) : ExpressionTypingVisitor(facade) {
import java.util.Collections;
import java.util.List;
import static org.jetbrains.kotlin.diagnostics.Errors.*; override fun visitNamedFunction(function: JetNamedFunction, data: ExpressionTypingContext): JetTypeInfo {
import static org.jetbrains.kotlin.resolve.BindingContext.*; return visitNamedFunction(function, data, false, null)
import static org.jetbrains.kotlin.resolve.source.SourcePackage.toSourceElement;
import static org.jetbrains.kotlin.types.TypeUtils.*;
import static org.jetbrains.kotlin.types.expressions.CoercionStrategy.COERCION_TO_UNIT;
public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
protected ClosureExpressionsTypingVisitor(@NotNull ExpressionTypingInternals facade) {
super(facade);
} }
@Override public fun visitNamedFunction(
public JetTypeInfo visitNamedFunction( function: JetNamedFunction,
@NotNull JetNamedFunction function, ExpressionTypingContext data context: ExpressionTypingContext,
) { isStatement: Boolean,
return visitNamedFunction(function, data, false, null); statementScope: WritableScope? // must be not null if isStatement
} ): JetTypeInfo {
if (!isStatement) {
public JetTypeInfo visitNamedFunction( // function expression
@NotNull JetNamedFunction function,
@NotNull ExpressionTypingContext context,
boolean isStatement,
@Nullable WritableScope statementScope // must be not null if isStatement
) {
if (!isStatement) { // function expression
if (!function.getTypeParameters().isEmpty()) { if (!function.getTypeParameters().isEmpty()) {
context.trace.report(TYPE_PARAMETERS_NOT_ALLOWED.on(function)); context.trace.report(TYPE_PARAMETERS_NOT_ALLOWED.on(function))
} }
for (JetParameter parameter : function.getValueParameters()) { for (parameter in function.getValueParameters()) {
if (parameter.hasDefaultValue()) { if (parameter.hasDefaultValue()) {
context.trace.report(FUNCTION_EXPRESSION_PARAMETER_WITH_DEFAULT_VALUE.on(parameter)); context.trace.report(FUNCTION_EXPRESSION_PARAMETER_WITH_DEFAULT_VALUE.on(parameter))
} }
if (parameter.isVarArg()) { if (parameter.isVarArg()) {
context.trace.report(USELESS_VARARG_ON_PARAMETER.on(parameter)); context.trace.report(USELESS_VARARG_ON_PARAMETER.on(parameter))
} }
} }
} }
ExpressionTypingServices services = components.expressionTypingServices; val services = components.expressionTypingServices
SimpleFunctionDescriptor functionDescriptor; val functionDescriptor: SimpleFunctionDescriptor
if (isStatement) { if (isStatement) {
functionDescriptor = services.getDescriptorResolver(). functionDescriptor = services.getDescriptorResolver().resolveFunctionDescriptorWithAnnotationArguments(
resolveFunctionDescriptorWithAnnotationArguments( context.scope.getContainingDeclaration(), context.scope, function, context.trace, context.dataFlowInfo)
context.scope.getContainingDeclaration(), context.scope, function, context.trace, context.dataFlowInfo); assert(statementScope != null) {
assert statementScope != null : "statementScope must be not null for function: " + "statementScope must be not null for function: " + function.getName() + " at location " + DiagnosticUtils.atLocation(function)
function.getName() + }
" at location " + statementScope!!.addFunctionDescriptor(functionDescriptor)
DiagnosticUtils.atLocation(function);
statementScope.addFunctionDescriptor(functionDescriptor);
} }
else { else {
functionDescriptor = services.getDescriptorResolver().resolveFunctionExpressionDescriptor( functionDescriptor = services.getDescriptorResolver().resolveFunctionExpressionDescriptor(
context.scope.getContainingDeclaration(), context.scope, function, context.trace, context.dataFlowInfo); context.scope.getContainingDeclaration(), context.scope, function, context.trace, context.dataFlowInfo)
} }
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(context.scope, functionDescriptor, context.trace); val functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(context.scope, functionDescriptor, context.trace)
services.checkFunctionReturnType(functionInnerScope, function, functionDescriptor, context.dataFlowInfo, null, context.trace); services.checkFunctionReturnType(functionInnerScope, function, functionDescriptor, context.dataFlowInfo, null, context.trace)
services.resolveValueParameters(function.getValueParameters(), functionDescriptor.getValueParameters(), context.scope, services.resolveValueParameters(function.getValueParameters(), functionDescriptor.getValueParameters(), context.scope,
context.dataFlowInfo, context.trace); context.dataFlowInfo, context.trace);
ModifiersChecker.create(context.trace, components.additionalCheckerProvider).checkModifiersForLocalDeclaration(function, ModifiersChecker.create(context.trace, components.additionalCheckerProvider)
functionDescriptor); .checkModifiersForLocalDeclaration(function, functionDescriptor)
if (!function.hasBody()) { if (!function.hasBody()) {
context.trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor)); context.trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor))
} }
if (isStatement) { if (isStatement) {
return DataFlowUtils.checkStatementType(function, context, context.dataFlowInfo); return DataFlowUtils.checkStatementType(function, context as ResolutionContext<*>, context.dataFlowInfo)
} }
else { else {
return DataFlowUtils.checkType(createFunctionType(functionDescriptor), function, context, context.dataFlowInfo); return DataFlowUtils.checkType(createFunctionType(functionDescriptor), function, context as ResolutionContext<*>, context.dataFlowInfo)
} }
} }
@Nullable private fun createFunctionType(functionDescriptor: SimpleFunctionDescriptor): JetType? {
private JetType createFunctionType(@NotNull SimpleFunctionDescriptor functionDescriptor) { val receiverType = functionDescriptor.getExtensionReceiverParameter()?.getType()
JetType receiverType = functionDescriptor.getExtensionReceiverParameter() != null
? functionDescriptor.getExtensionReceiverParameter().getType()
: null;
JetType returnType = functionDescriptor.getReturnType(); val returnType = functionDescriptor.getReturnType()
if (returnType == null) { if (returnType == null) {
return null; return null
} }
List<JetType> parameters = val parameters = functionDescriptor.getValueParameters().map {
ContainerUtil.map(functionDescriptor.getValueParameters(), new Function<ValueParameterDescriptor, JetType>() { it.getType()
@Override }
public JetType fun(ValueParameterDescriptor descriptor) {
return descriptor.getType();
}
});
return components.builtIns.getFunctionType(Annotations.EMPTY, receiverType, parameters, returnType); return components.builtIns.getFunctionType(Annotations.EMPTY, receiverType, parameters, returnType)
} }
@Override override fun visitFunctionLiteralExpression(expression: JetFunctionLiteralExpression, context: ExpressionTypingContext): JetTypeInfo? {
public JetTypeInfo visitFunctionLiteralExpression(@NotNull JetFunctionLiteralExpression expression, ExpressionTypingContext context) { if (!expression.getFunctionLiteral().hasBody()) return null
if (!expression.getFunctionLiteral().hasBody()) return null;
JetType expectedType = context.expectedType; val expectedType = context.expectedType
boolean functionTypeExpected = !noExpectedType(expectedType) && KotlinBuiltIns.isFunctionOrExtensionFunctionType( val functionTypeExpected = !noExpectedType(expectedType) && KotlinBuiltIns.isFunctionOrExtensionFunctionType(expectedType)
expectedType);
AnonymousFunctionDescriptor functionDescriptor = createFunctionDescriptor(expression, context, functionTypeExpected); val functionDescriptor = createFunctionDescriptor(expression, context, functionTypeExpected)
JetType safeReturnType = computeReturnType(expression, context, functionDescriptor, functionTypeExpected); val safeReturnType = computeReturnType(expression, context, functionDescriptor, functionTypeExpected)
functionDescriptor.setReturnType(safeReturnType); functionDescriptor.setReturnType(safeReturnType)
JetType receiver = DescriptorUtils.getReceiverParameterType(functionDescriptor.getExtensionReceiverParameter()); val receiver = DescriptorUtils.getReceiverParameterType(functionDescriptor.getExtensionReceiverParameter())
List<JetType> valueParametersTypes = ExpressionTypingUtils.getValueParametersTypes(functionDescriptor.getValueParameters()); val valueParametersTypes = ExpressionTypingUtils.getValueParametersTypes(functionDescriptor.getValueParameters())
JetType resultType = components.builtIns.getFunctionType( val resultType = components.builtIns.getFunctionType(Annotations.EMPTY, receiver, valueParametersTypes, safeReturnType)
Annotations.EMPTY, receiver, valueParametersTypes, safeReturnType);
if (!noExpectedType(expectedType) && KotlinBuiltIns.isFunctionOrExtensionFunctionType(expectedType)) { if (!noExpectedType(expectedType) && KotlinBuiltIns.isFunctionOrExtensionFunctionType(expectedType)) {
// all checks were done before // all checks were done before
return JetTypeInfo.create(resultType, context.dataFlowInfo); return JetTypeInfo.create(resultType, context.dataFlowInfo)
} }
return DataFlowUtils.checkType(resultType, expression, context, context.dataFlowInfo); return DataFlowUtils.checkType(resultType, expression, context as ResolutionContext<*>, context.dataFlowInfo)
} }
@NotNull private fun createFunctionDescriptor(
private AnonymousFunctionDescriptor createFunctionDescriptor( expression: JetFunctionLiteralExpression,
@NotNull JetFunctionLiteralExpression expression, context: ExpressionTypingContext,
@NotNull ExpressionTypingContext context, functionTypeExpected: Boolean
boolean functionTypeExpected ): AnonymousFunctionDescriptor {
) { val functionLiteral = expression.getFunctionLiteral()
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral(); val receiverTypeRef = functionLiteral.getReceiverTypeReference()
JetTypeReference receiverTypeRef = functionLiteral.getReceiverTypeReference(); val functionDescriptor = AnonymousFunctionDescriptor(context.scope.getContainingDeclaration(), Annotations.EMPTY,
AnonymousFunctionDescriptor functionDescriptor = new AnonymousFunctionDescriptor( CallableMemberDescriptor.Kind.DECLARATION, functionLiteral.toSourceElement())
context.scope.getContainingDeclaration(), Annotations.EMPTY, CallableMemberDescriptor.Kind.DECLARATION,
toSourceElement(functionLiteral)
);
List<ValueParameterDescriptor> valueParameterDescriptors = createValueParameterDescriptors(context, functionLiteral, val valueParameterDescriptors = createValueParameterDescriptors(context, functionLiteral, functionDescriptor, functionTypeExpected)
functionDescriptor, functionTypeExpected);
JetType effectiveReceiverType; val effectiveReceiverType: JetType?
if (receiverTypeRef == null) { if (receiverTypeRef == null) {
if (functionTypeExpected) { if (functionTypeExpected) {
effectiveReceiverType = KotlinBuiltIns.getReceiverType(context.expectedType); effectiveReceiverType = KotlinBuiltIns.getReceiverType(context.expectedType)
} }
else { else {
effectiveReceiverType = null; effectiveReceiverType = null
} }
} }
else { else {
effectiveReceiverType = components.expressionTypingServices.getTypeResolver().resolveType(context.scope, receiverTypeRef, context.trace, true); effectiveReceiverType = components.expressionTypingServices.getTypeResolver().resolveType(context.scope, receiverTypeRef,
context.trace, true)
} }
functionDescriptor.initialize(effectiveReceiverType, functionDescriptor.initialize(effectiveReceiverType, ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER, listOf(),
ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER, valueParameterDescriptors, /*unsubstitutedReturnType = */ null, Modality.FINAL, Visibilities.LOCAL)
Collections.<TypeParameterDescriptorImpl>emptyList(), BindingContextUtils.recordFunctionDeclarationToDescriptor(context.trace, functionLiteral, functionDescriptor)
valueParameterDescriptors, return functionDescriptor
/*unsubstitutedReturnType = */ null,
Modality.FINAL,
Visibilities.LOCAL
);
BindingContextUtils.recordFunctionDeclarationToDescriptor(context.trace, functionLiteral, functionDescriptor);
return functionDescriptor;
} }
@NotNull private fun createValueParameterDescriptors(
private List<ValueParameterDescriptor> createValueParameterDescriptors( context: ExpressionTypingContext,
@NotNull ExpressionTypingContext context, functionLiteral: JetFunctionLiteral,
@NotNull JetFunctionLiteral functionLiteral, functionDescriptor: FunctionDescriptorImpl,
@NotNull FunctionDescriptorImpl functionDescriptor, functionTypeExpected: Boolean
boolean functionTypeExpected ): List<ValueParameterDescriptor> {
) { val valueParameterDescriptors = Lists.newArrayList<ValueParameterDescriptor>()
List<ValueParameterDescriptor> valueParameterDescriptors = Lists.newArrayList(); val declaredValueParameters = functionLiteral.getValueParameters()
List<JetParameter> declaredValueParameters = functionLiteral.getValueParameters();
List<ValueParameterDescriptor> expectedValueParameters = (functionTypeExpected) val expectedValueParameters = if (functionTypeExpected) KotlinBuiltIns.getValueParameters(functionDescriptor, context.expectedType)
? KotlinBuiltIns.getValueParameters(functionDescriptor, context.expectedType) else null
: null;
JetParameterList valueParameterList = functionLiteral.getValueParameterList(); val valueParameterList = functionLiteral.getValueParameterList()
boolean hasDeclaredValueParameters = valueParameterList != null; val hasDeclaredValueParameters = valueParameterList != null
if (functionTypeExpected && !hasDeclaredValueParameters && expectedValueParameters.size() == 1) { if (functionTypeExpected && !hasDeclaredValueParameters && expectedValueParameters!!.size() == 1) {
ValueParameterDescriptor valueParameterDescriptor = expectedValueParameters.get(0); val valueParameterDescriptor = expectedValueParameters!!.get(0)
ValueParameterDescriptor it = new ValueParameterDescriptorImpl( val it = ValueParameterDescriptorImpl(functionDescriptor, null, 0, Annotations.EMPTY, Name.identifier("it"),
functionDescriptor, null, 0, Annotations.EMPTY, Name.identifier("it"), valueParameterDescriptor.getType(), valueParameterDescriptor.hasDefaultValue(),
valueParameterDescriptor.getType(), valueParameterDescriptor.hasDefaultValue(), valueParameterDescriptor.getVarargElementType(), valueParameterDescriptor.getVarargElementType(), SourceElement.NO_SOURCE)
SourceElement.NO_SOURCE valueParameterDescriptors.add(it)
); context.trace.record<ValueParameterDescriptor>(AUTO_CREATED_IT, it)
valueParameterDescriptors.add(it);
context.trace.record(AUTO_CREATED_IT, it);
} }
else { else {
if (expectedValueParameters != null && declaredValueParameters.size() != expectedValueParameters.size()) { if (expectedValueParameters != null && declaredValueParameters.size() != expectedValueParameters.size()) {
List<JetType> expectedParameterTypes = ExpressionTypingUtils.getValueParametersTypes(expectedValueParameters); val expectedParameterTypes = ExpressionTypingUtils.getValueParametersTypes(expectedValueParameters)
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 (i in declaredValueParameters.indices) {
ValueParameterDescriptor valueParameterDescriptor = createValueParameterDescriptor( val valueParameterDescriptor = createValueParameterDescriptor(context, functionDescriptor, declaredValueParameters, expectedValueParameters, i)
context, functionDescriptor, declaredValueParameters, expectedValueParameters, i); valueParameterDescriptors.add(valueParameterDescriptor)
valueParameterDescriptors.add(valueParameterDescriptor);
} }
} }
return valueParameterDescriptors; return valueParameterDescriptors
} }
@NotNull private fun createValueParameterDescriptor(
private ValueParameterDescriptor createValueParameterDescriptor( context: ExpressionTypingContext,
@NotNull ExpressionTypingContext context, functionDescriptor: FunctionDescriptorImpl,
@NotNull FunctionDescriptorImpl functionDescriptor, declaredValueParameters: List<JetParameter>,
@NotNull List<JetParameter> declaredValueParameters, expectedValueParameters: List<ValueParameterDescriptor>?,
@Nullable List<ValueParameterDescriptor> expectedValueParameters, index: Int
int index ): ValueParameterDescriptor {
) { val declaredParameter = declaredValueParameters.get(index)
JetParameter declaredParameter = declaredValueParameters.get(index); val typeReference = declaredParameter.getTypeReference()
JetTypeReference typeReference = declaredParameter.getTypeReference();
JetType expectedType; val expectedType: JetType?
if (expectedValueParameters != null && index < expectedValueParameters.size()) { if (expectedValueParameters != null && index < expectedValueParameters.size()) {
expectedType = expectedValueParameters.get(index).getType(); expectedType = expectedValueParameters.get(index).getType()
} }
else { else {
expectedType = null; expectedType = null
} }
JetType type; val type: JetType
if (typeReference != null) { if (typeReference != null) {
type = components.expressionTypingServices.getTypeResolver().resolveType(context.scope, typeReference, context.trace, true); type = components.expressionTypingServices.getTypeResolver().resolveType(context.scope, typeReference, context.trace, true)
if (expectedType != null) { if (expectedType != null) {
if (!JetTypeChecker.DEFAULT.isSubtypeOf(expectedType, type)) { if (!JetTypeChecker.DEFAULT.isSubtypeOf(expectedType, type)) {
context.trace.report(EXPECTED_PARAMETER_TYPE_MISMATCH.on(declaredParameter, expectedType)); context.trace.report(EXPECTED_PARAMETER_TYPE_MISMATCH.on(declaredParameter, expectedType))
} }
} }
} }
else { else {
boolean containsUninferredParameter = TypeUtils.containsSpecialType(expectedType, new Function1<JetType, Boolean>() { val containsUninferredParameter = TypeUtils.containsSpecialType(expectedType) {
@Override TypeUtils.isDontCarePlaceholder(it) || ErrorUtils.isUninferredParameter(it)
public Boolean invoke(JetType type) {
return TypeUtils.isDontCarePlaceholder(type) || ErrorUtils.isUninferredParameter(type);
} }
});
if (expectedType == null || containsUninferredParameter) { if (expectedType == null || containsUninferredParameter) {
context.trace.report(CANNOT_INFER_PARAMETER_TYPE.on(declaredParameter)); context.trace.report(CANNOT_INFER_PARAMETER_TYPE.on(declaredParameter))
} }
if (expectedType != null) { if (expectedType != null) {
type = expectedType; type = expectedType
} }
else { else {
type = CANT_INFER_LAMBDA_PARAM_TYPE; type = CANT_INFER_LAMBDA_PARAM_TYPE
} }
} }
return components.expressionTypingServices.getDescriptorResolver().resolveValueParameterDescriptorWithAnnotationArguments( return components.expressionTypingServices.getDescriptorResolver()
context.scope, functionDescriptor, declaredParameter, index, type, context.trace); .resolveValueParameterDescriptorWithAnnotationArguments(context.scope, functionDescriptor, declaredParameter,
index, type, context.trace)
} }
@NotNull private fun computeReturnType(
private JetType computeReturnType( expression: JetFunctionLiteralExpression,
@NotNull JetFunctionLiteralExpression expression, context: ExpressionTypingContext,
@NotNull ExpressionTypingContext context, functionDescriptor: SimpleFunctionDescriptorImpl,
@NotNull SimpleFunctionDescriptorImpl functionDescriptor, functionTypeExpected: Boolean
boolean functionTypeExpected ): JetType {
) { val expectedReturnType = if (functionTypeExpected) KotlinBuiltIns.getReturnTypeFromFunctionType(context.expectedType) else null
JetType expectedReturnType = functionTypeExpected ? KotlinBuiltIns.getReturnTypeFromFunctionType(context.expectedType) : null; val returnType = computeUnsafeReturnType(expression, context, functionDescriptor, expectedReturnType);
JetType returnType = computeUnsafeReturnType(expression, context, functionDescriptor, expectedReturnType);
if (!expression.getFunctionLiteral().hasDeclaredReturnType() && functionTypeExpected) { if (!expression.getFunctionLiteral().hasDeclaredReturnType() && functionTypeExpected) {
if (KotlinBuiltIns.isUnit(expectedReturnType)) { if (KotlinBuiltIns.isUnit(expectedReturnType!!)) {
return components.builtIns.getUnitType(); return components.builtIns.getUnitType()
} }
} }
return returnType == null ? CANT_INFER_LAMBDA_PARAM_TYPE : returnType; return returnType ?: CANT_INFER_LAMBDA_PARAM_TYPE
} }
@Nullable
private JetType computeUnsafeReturnType(
@NotNull JetFunctionLiteralExpression expression,
@NotNull ExpressionTypingContext context,
@NotNull SimpleFunctionDescriptorImpl functionDescriptor,
@Nullable JetType expectedReturnType
) {
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
JetBlockExpression bodyExpression = functionLiteral.getBodyExpression();
assert bodyExpression != null;
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(context.scope, functionDescriptor, context.trace); private fun computeUnsafeReturnType(
JetTypeReference returnTypeRef = functionLiteral.getTypeReference(); expression: JetFunctionLiteralExpression,
JetType declaredReturnType = null; context: ExpressionTypingContext,
if (returnTypeRef != null) { functionDescriptor: SimpleFunctionDescriptorImpl,
declaredReturnType = components.expressionTypingServices.getTypeResolver().resolveType(context.scope, returnTypeRef, context.trace, true); expectedReturnType: JetType?
// This is needed for ControlStructureTypingVisitor#visitReturnExpression() to properly type-check returned expressions ): JetType? {
functionDescriptor.setReturnType(declaredReturnType); val functionLiteral = expression.getFunctionLiteral()
if (expectedReturnType != null) { val declaredReturnType = functionLiteral.getTypeReference()?.let {
if (!JetTypeChecker.DEFAULT.isSubtypeOf(declaredReturnType, expectedReturnType)) { val type = components.expressionTypingServices.getTypeResolver().resolveType(context.scope, it, context.trace, true)
context.trace.report(EXPECTED_RETURN_TYPE_MISMATCH.on(returnTypeRef, expectedReturnType)); if (expectedReturnType != null && !JetTypeChecker.DEFAULT.isSubtypeOf(type, expectedReturnType)) {
} context.trace.report(EXPECTED_RETURN_TYPE_MISMATCH.on(it, expectedReturnType))
} }
type
} }
// Type-check the body val expectedType = declaredReturnType ?: (expectedReturnType ?: NO_EXPECTED_TYPE)
JetType expectedType = declaredReturnType != null val functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(context.scope, functionDescriptor, context.trace)
? declaredReturnType val newContext = context.replaceScope(functionInnerScope).replaceExpectedType(expectedType)
: (expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE);
ExpressionTypingContext newContext = context.replaceScope(functionInnerScope).replaceExpectedType(expectedType);
context.trace.record(EXPECTED_RETURN_TYPE, functionLiteral, expectedType);
JetType typeOfBodyExpression = // needed for error reporting
components.expressionTypingServices.getBlockReturnedType(bodyExpression, COERCION_TO_UNIT, newContext).getType();
if (declaredReturnType != null) { // This is needed for ControlStructureTypingVisitor#visitReturnExpression() to properly type-check returned expressions
return declaredReturnType; context.trace.record(EXPECTED_RETURN_TYPE, functionLiteral, expectedType)
} val typeOfBodyExpression = // Type-check the body
else { components.expressionTypingServices.getBlockReturnedType(functionLiteral.getBodyExpression(), COERCION_TO_UNIT, newContext).getType()
return computeReturnTypeBasedOnReturnExpressions(functionLiteral, context, typeOfBodyExpression);
} return declaredReturnType ?: computeReturnTypeBasedOnReturnExpressions(functionLiteral, context, typeOfBodyExpression)
} }
@Nullable private fun computeReturnTypeBasedOnReturnExpressions(
private JetType computeReturnTypeBasedOnReturnExpressions( functionLiteral: JetFunctionLiteral,
@NotNull JetFunctionLiteral functionLiteral, context: ExpressionTypingContext,
@NotNull ExpressionTypingContext context, typeOfBodyExpression: JetType?
@Nullable JetType typeOfBodyExpression ): JetType? {
) { val returnedExpressionTypes = Lists.newArrayList<JetType>()
List<JetType> returnedExpressionTypes = Lists.newArrayList();
boolean hasEmptyReturn = false; var hasEmptyReturn = false
Collection<JetReturnExpression> returnExpressions = collectReturns(functionLiteral, context.trace); val returnExpressions = collectReturns(functionLiteral, context.trace)
for (JetReturnExpression returnExpression : returnExpressions) { for (returnExpression in returnExpressions) {
JetExpression returnedExpression = returnExpression.getReturnedExpression(); val returnedExpression = returnExpression.getReturnedExpression()
if (returnedExpression == null) { if (returnedExpression == null) {
hasEmptyReturn = true; hasEmptyReturn = true
} }
else { else {
// the type should have been computed by getBlockReturnedType() above, but can be null, if returnExpression contains some error // the type should have been computed by getBlockReturnedType() above, but can be null, if returnExpression contains some error
ContainerUtil.addIfNotNull(returnedExpressionTypes, context.trace.get(EXPRESSION_TYPE, returnedExpression)); returnedExpressionTypes.addIfNotNull(context.trace.get<JetExpression, JetType>(EXPRESSION_TYPE, returnedExpression))
} }
} }
if (hasEmptyReturn) { if (hasEmptyReturn) {
for (JetReturnExpression returnExpression : returnExpressions) { for (returnExpression in returnExpressions) {
JetExpression returnedExpression = returnExpression.getReturnedExpression(); val returnedExpression = returnExpression.getReturnedExpression()
if (returnedExpression != null) { if (returnedExpression != null) {
JetType type = context.trace.get(EXPRESSION_TYPE, returnedExpression); val type = context.trace.get<JetExpression, JetType>(EXPRESSION_TYPE, returnedExpression)
if (type == null || !KotlinBuiltIns.isUnit(type)) { if (type == null || !KotlinBuiltIns.isUnit(type)) {
context.trace.report(RETURN_TYPE_MISMATCH.on(returnedExpression, components.builtIns.getUnitType())); context.trace.report(RETURN_TYPE_MISMATCH.on(returnedExpression, components.builtIns.getUnitType()))
} }
} }
} }
return components.builtIns.getUnitType(); return components.builtIns.getUnitType()
} }
returnedExpressionTypes.addIfNotNull(typeOfBodyExpression)
ContainerUtil.addIfNotNull(returnedExpressionTypes, typeOfBodyExpression); if (returnedExpressionTypes.isEmpty()) return null
return CommonSupertypes.commonSupertype(returnedExpressionTypes)
if (returnedExpressionTypes.isEmpty()) return null;
return CommonSupertypes.commonSupertype(returnedExpressionTypes);
} }
private static Collection<JetReturnExpression> collectReturns( private fun collectReturns(functionLiteral: JetFunctionLiteral, trace: BindingTrace): Collection<JetReturnExpression> {
@NotNull final JetFunctionLiteral functionLiteral, val result = Lists.newArrayList<JetReturnExpression>()
@NotNull final BindingTrace trace val bodyExpression = functionLiteral.getBodyExpression()
) { bodyExpression?.accept(object : JetTreeVisitor<MutableList<JetReturnExpression>>() {
Collection<JetReturnExpression> result = Lists.newArrayList(); override fun visitReturnExpression(expression: JetReturnExpression, data: MutableList<JetReturnExpression>): Void? {
JetBlockExpression bodyExpression = functionLiteral.getBodyExpression(); data.add(expression)
assert bodyExpression != null; return null
bodyExpression.accept(
new JetTreeVisitor<Collection<JetReturnExpression>>() {
@Override
public Void visitReturnExpression(
@NotNull JetReturnExpression expression, Collection<JetReturnExpression> data
) {
data.add(expression);
return null;
}
},
result
);
return ContainerUtil.mapNotNull(result, new Function<JetReturnExpression, JetReturnExpression>() {
@Override
public JetReturnExpression fun(@NotNull JetReturnExpression returnExpression) {
JetSimpleNameExpression label = returnExpression.getTargetLabel();
if (label == null) {
// No label => non-local return
return null;
}
PsiElement labelTarget = trace.get(BindingContext.LABEL_TARGET, label);
if (labelTarget != functionLiteral) {
// Either a local return of inner lambda/function or a non-local return
return null;
}
return returnExpression;
} }
}); }, result)
return result.filter {
// No label => non-local return
// Either a local return of inner lambda/function or a non-local return
it.getTargetLabel()?.let { trace.get(BindingContext.LABEL_TARGET, it) } == functionLiteral
}
} }
} }