Merge remote branch 'origin/master'
This commit is contained in:
+72
-54
@@ -24,6 +24,7 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
|
* @author svtk
|
||||||
*/
|
*/
|
||||||
public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
|
public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
|
||||||
protected ClosureExpressionsTypingVisitor(@NotNull ExpressionTypingInternals facade) {
|
protected ClosureExpressionsTypingVisitor(@NotNull ExpressionTypingInternals facade) {
|
||||||
@@ -61,8 +62,54 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
@Override
|
@Override
|
||||||
public JetType visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, ExpressionTypingContext context) {
|
public JetType visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, ExpressionTypingContext context) {
|
||||||
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
|
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
|
||||||
if (functionLiteral.getBodyExpression() == null) return null;
|
JetBlockExpression bodyExpression = functionLiteral.getBodyExpression();
|
||||||
|
if (bodyExpression == null) return null;
|
||||||
|
|
||||||
|
JetType expectedType = context.expectedType;
|
||||||
|
boolean functionTypeExpected = expectedType != TypeUtils.NO_EXPECTED_TYPE && JetStandardClasses.isFunctionType(expectedType);
|
||||||
|
|
||||||
|
FunctionDescriptorImpl functionDescriptor = createFunctionDescriptor(expression, context, functionTypeExpected);
|
||||||
|
|
||||||
|
List<JetType> parameterTypes = Lists.newArrayList();
|
||||||
|
List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters();
|
||||||
|
for (ValueParameterDescriptor valueParameter : valueParameters) {
|
||||||
|
parameterTypes.add(valueParameter.getOutType());
|
||||||
|
}
|
||||||
|
ReceiverDescriptor receiverParameter = functionDescriptor.getReceiverParameter();
|
||||||
|
JetType receiver = receiverParameter != NO_RECEIVER ? receiverParameter.getType() : null;
|
||||||
|
|
||||||
|
JetType returnType = TypeUtils.NO_EXPECTED_TYPE;
|
||||||
|
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(context.scope, functionDescriptor, context.trace);
|
||||||
|
JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef();
|
||||||
|
if (returnTypeRef != null) {
|
||||||
|
returnType = context.getTypeResolver().resolveType(context.scope, returnTypeRef);
|
||||||
|
context.getServices().checkFunctionReturnType(expression, context.replaceScope(functionInnerScope).
|
||||||
|
replaceExpectedType(returnType).replaceExpectedReturnType(returnType).replaceDataFlowInfo(context.dataFlowInfo));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (functionTypeExpected) {
|
||||||
|
returnType = JetStandardClasses.obtainReturnTypeFromFunctionType(expectedType);
|
||||||
|
}
|
||||||
|
returnType = context.getServices().getBlockReturnedType(functionInnerScope, bodyExpression, CoercionStrategy.COERCION_TO_UNIT,
|
||||||
|
context.replaceExpectedType(returnType).replaceExpectedReturnType(returnType));
|
||||||
|
}
|
||||||
|
JetType safeReturnType = returnType == null ? ErrorUtils.createErrorType("<return type>") : returnType;
|
||||||
|
functionDescriptor.setReturnType(safeReturnType);
|
||||||
|
|
||||||
|
boolean hasDeclaredValueParameters = functionLiteral.getValueParameterList() != null;
|
||||||
|
if (!hasDeclaredValueParameters && functionTypeExpected) {
|
||||||
|
JetType expectedReturnType = JetStandardClasses.obtainReturnTypeFromFunctionType(expectedType);
|
||||||
|
if (JetStandardClasses.isUnit(expectedReturnType)) {
|
||||||
|
functionDescriptor.setReturnType(JetStandardClasses.getUnitType());
|
||||||
|
return DataFlowUtils.checkType(JetStandardClasses.getFunctionType(Collections.<AnnotationDescriptor>emptyList(), receiver, parameterTypes, JetStandardClasses.getUnitType()), expression, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return DataFlowUtils.checkType(JetStandardClasses.getFunctionType(Collections.<AnnotationDescriptor>emptyList(), receiver, parameterTypes, safeReturnType), expression, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FunctionDescriptorImpl createFunctionDescriptor(JetFunctionLiteralExpression expression, ExpressionTypingContext context, boolean functionTypeExpected) {
|
||||||
|
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
|
||||||
JetTypeReference receiverTypeRef = functionLiteral.getReceiverTypeRef();
|
JetTypeReference receiverTypeRef = functionLiteral.getReceiverTypeRef();
|
||||||
final JetType receiverType;
|
final JetType receiverType;
|
||||||
if (receiverTypeRef != null) {
|
if (receiverTypeRef != null) {
|
||||||
@@ -71,27 +118,43 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
ReceiverDescriptor implicitReceiver = context.scope.getImplicitReceiver();
|
ReceiverDescriptor implicitReceiver = context.scope.getImplicitReceiver();
|
||||||
receiverType = implicitReceiver.exists() ? implicitReceiver.getType() : null;
|
receiverType = implicitReceiver.exists() ? implicitReceiver.getType() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl(
|
FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl(
|
||||||
context.scope.getContainingDeclaration(), Collections.<AnnotationDescriptor>emptyList(), "<anonymous>");
|
context.scope.getContainingDeclaration(), Collections.<AnnotationDescriptor>emptyList(), "<anonymous>");
|
||||||
|
|
||||||
List<JetType> parameterTypes = Lists.newArrayList();
|
List<ValueParameterDescriptor> valueParameterDescriptors = createValueParameterDescriptors(context, functionLiteral, functionDescriptor, functionTypeExpected);
|
||||||
|
|
||||||
|
JetType effectiveReceiverType;
|
||||||
|
if (receiverTypeRef == null) {
|
||||||
|
if (functionTypeExpected) {
|
||||||
|
effectiveReceiverType = JetStandardClasses.getReceiverType(context.expectedType);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
effectiveReceiverType = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
effectiveReceiverType = receiverType;
|
||||||
|
}
|
||||||
|
functionDescriptor.initialize(effectiveReceiverType, NO_RECEIVER, Collections.<TypeParameterDescriptor>emptyList(), valueParameterDescriptors, null, Modality.FINAL, Visibility.LOCAL);
|
||||||
|
context.trace.record(BindingContext.FUNCTION, expression, functionDescriptor);
|
||||||
|
return functionDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ValueParameterDescriptor> createValueParameterDescriptors(ExpressionTypingContext context, JetFunctionLiteral functionLiteral, FunctionDescriptorImpl functionDescriptor, boolean functionTypeExpected) {
|
||||||
List<ValueParameterDescriptor> valueParameterDescriptors = Lists.newArrayList();
|
List<ValueParameterDescriptor> valueParameterDescriptors = Lists.newArrayList();
|
||||||
List<JetParameter> declaredValueParameters = functionLiteral.getValueParameters();
|
List<JetParameter> declaredValueParameters = functionLiteral.getValueParameters();
|
||||||
JetType expectedType = context.expectedType;
|
|
||||||
|
|
||||||
boolean functionTypeExpected = expectedType != TypeUtils.NO_EXPECTED_TYPE && JetStandardClasses.isFunctionType(expectedType);
|
|
||||||
List<ValueParameterDescriptor> expectedValueParameters = (functionTypeExpected)
|
List<ValueParameterDescriptor> expectedValueParameters = (functionTypeExpected)
|
||||||
? JetStandardClasses.getValueParameters(functionDescriptor, expectedType)
|
? JetStandardClasses.getValueParameters(functionDescriptor, context.expectedType)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
if (functionTypeExpected && declaredValueParameters.isEmpty() && expectedValueParameters.size() == 1) {
|
boolean hasDeclaredValueParameters = functionLiteral.getValueParameterList() != null;
|
||||||
|
if (functionTypeExpected && !hasDeclaredValueParameters && expectedValueParameters.size() == 1) {
|
||||||
ValueParameterDescriptor valueParameterDescriptor = expectedValueParameters.get(0);
|
ValueParameterDescriptor valueParameterDescriptor = expectedValueParameters.get(0);
|
||||||
ValueParameterDescriptor it = new ValueParameterDescriptorImpl(
|
ValueParameterDescriptor it = new ValueParameterDescriptorImpl(
|
||||||
functionDescriptor, 0, Collections.<AnnotationDescriptor>emptyList(), "it", valueParameterDescriptor.getInType(), valueParameterDescriptor.getOutType(), valueParameterDescriptor.hasDefaultValue(), valueParameterDescriptor.getVarargElementType()
|
functionDescriptor, 0, Collections.<AnnotationDescriptor>emptyList(), "it", valueParameterDescriptor.getInType(), valueParameterDescriptor.getOutType(), valueParameterDescriptor.hasDefaultValue(), valueParameterDescriptor.getVarargElementType()
|
||||||
);
|
);
|
||||||
valueParameterDescriptors.add(it);
|
valueParameterDescriptors.add(it);
|
||||||
parameterTypes.add(it.getOutType());
|
|
||||||
context.trace.record(AUTO_CREATED_IT, it);
|
context.trace.record(AUTO_CREATED_IT, it);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -113,54 +176,9 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ValueParameterDescriptor valueParameterDescriptor = context.getClassDescriptorResolver().resolveValueParameterDescriptor(functionDescriptor, declaredParameter, i, type);
|
ValueParameterDescriptor valueParameterDescriptor = context.getClassDescriptorResolver().resolveValueParameterDescriptor(functionDescriptor, declaredParameter, i, type);
|
||||||
parameterTypes.add(valueParameterDescriptor.getOutType());
|
|
||||||
valueParameterDescriptors.add(valueParameterDescriptor);
|
valueParameterDescriptors.add(valueParameterDescriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return valueParameterDescriptors;
|
||||||
JetType effectiveReceiverType;
|
|
||||||
if (receiverTypeRef == null) {
|
|
||||||
if (functionTypeExpected) {
|
|
||||||
effectiveReceiverType = JetStandardClasses.getReceiverType(expectedType);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
effectiveReceiverType = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
effectiveReceiverType = receiverType;
|
|
||||||
}
|
|
||||||
functionDescriptor.initialize(effectiveReceiverType, NO_RECEIVER, Collections.<TypeParameterDescriptor>emptyList(), valueParameterDescriptors, null, Modality.FINAL, Visibility.LOCAL);
|
|
||||||
context.trace.record(BindingContext.FUNCTION, expression, functionDescriptor);
|
|
||||||
|
|
||||||
JetType returnType = TypeUtils.NO_EXPECTED_TYPE;
|
|
||||||
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(context.scope, functionDescriptor, context.trace);
|
|
||||||
JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef();
|
|
||||||
if (returnTypeRef != null) {
|
|
||||||
returnType = context.getTypeResolver().resolveType(context.scope, returnTypeRef);
|
|
||||||
context.getServices().checkFunctionReturnType(expression, context.replaceScope(functionInnerScope).
|
|
||||||
replaceExpectedType(returnType).replaceExpectedReturnType(returnType).replaceDataFlowInfo(context.dataFlowInfo));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (functionTypeExpected) {
|
|
||||||
returnType = JetStandardClasses.obtainReturnTypeFromFunctionType(expectedType);
|
|
||||||
}
|
|
||||||
// }
|
|
||||||
returnType = context.getServices().getBlockReturnedType(functionInnerScope, functionLiteral.getBodyExpression(), CoercionStrategy.COERCION_TO_UNIT,
|
|
||||||
context.replaceExpectedType(returnType).replaceExpectedReturnType(returnType));
|
|
||||||
}
|
|
||||||
JetType safeReturnType = returnType == null ? ErrorUtils.createErrorType("<return type>") : returnType;
|
|
||||||
functionDescriptor.setReturnType(safeReturnType);
|
|
||||||
|
|
||||||
if (functionTypeExpected) {
|
|
||||||
JetType expectedReturnType = JetStandardClasses.obtainReturnTypeFromFunctionType(expectedType);
|
|
||||||
if (JetStandardClasses.isUnit(expectedReturnType)) {
|
|
||||||
functionDescriptor.setReturnType(expectedReturnType);
|
|
||||||
return DataFlowUtils.checkType(JetStandardClasses.getFunctionType(Collections.<AnnotationDescriptor>emptyList(), effectiveReceiverType, parameterTypes, expectedReturnType), expression, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return DataFlowUtils.checkType(JetStandardClasses.getFunctionType(Collections.<AnnotationDescriptor>emptyList(), effectiveReceiverType, parameterTypes, safeReturnType), expression, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
//KT-352 Function variable declaration type isn't checked inside a function body
|
||||||
|
|
||||||
|
namespace kt352
|
||||||
|
|
||||||
|
val f : fun(Any) : Unit = <!TYPE_MISMATCH!>{ () : Unit => }<!> //type mismatch
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val f : fun(Any) : Unit = <!TYPE_MISMATCH!>{ () : Unit => }<!> //!!! no error
|
||||||
|
}
|
||||||
|
|
||||||
|
class A() {
|
||||||
|
val f : fun(Any) : Unit = <!TYPE_MISMATCH!>{ () : Unit => }<!> //type mismatch
|
||||||
|
}
|
||||||
|
|
||||||
|
//more tests
|
||||||
|
val g : fun() : Unit = <!TYPE_MISMATCH!>{ (): Int => 42 }<!>
|
||||||
|
|
||||||
|
val h : fun() : Unit = { doSmth() }
|
||||||
|
|
||||||
|
fun doSmth(): Int = 42
|
||||||
|
fun doSmth(a: String) {}
|
||||||
|
|
||||||
|
val testIt : fun(Any) : Unit = {
|
||||||
|
if (it is String) {
|
||||||
|
doSmth(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user