From 0530df6f7b6b8c48e1ad1ed621b0ceaa80aaab89 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Wed, 27 Feb 2013 21:00:40 +0400 Subject: [PATCH] use TypeCheckingProcedure for generating constraints (in ConstraintSystemImpl) --- .../resolve/calls/CallExpressionResolver.java | 22 +- .../jet/lang/resolve/calls/CallResolver.java | 9 +- .../lang/resolve/calls/CallResolverUtil.java | 4 +- .../lang/resolve/calls/CandidateResolver.java | 12 +- .../calls/inference/ConstraintSystemImpl.java | 294 ++++++++---------- .../calls/inference/TypeConstraintsImpl.java | 14 +- .../calls/tasks/TracingStrategyImpl.java | 5 + .../jetbrains/jet/lang/types/TypeUtils.java | 6 +- .../noTypeParamsInReturnType.kt | 10 + .../tests/inference/dependantOnVariance.kt | 6 +- .../tests/inference/regressions/compareBy.kt | 9 + .../tests/inference/regressions/kt2838.kt | 2 +- .../checkers/JetDiagnosticsTestGenerated.java | 10 + 13 files changed, 202 insertions(+), 201 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/noTypeParamsInReturnType.kt create mode 100644 compiler/testData/diagnostics/tests/inference/regressions/compareBy.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java index ec3a470a2ad..f459b957426 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java @@ -26,7 +26,10 @@ import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.calls.context.*; +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace; import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults; import org.jetbrains.jet.lang.resolve.calls.util.CallMaker; import org.jetbrains.jet.lang.resolve.constants.ConstantUtils; @@ -149,7 +152,6 @@ public class CallExpressionResolver { @NotNull Call call, @NotNull JetExpression callExpression, @NotNull ReceiverValue receiver, @NotNull ResolutionContext context, @NotNull ResolveMode resolveMode, @NotNull boolean[] result ) { - CallResolver callResolver = expressionTypingServices.getCallResolver(); OverloadResolutionResults results = callResolver.resolveFunctionCall( BasicCallResolutionContext.create(context, call, resolveMode)); @@ -157,10 +159,14 @@ public class CallExpressionResolver { checkSuper(receiver, results, context.trace, callExpression); result[0] = true; if (results.isSingleResult() && resolveMode == ResolveMode.TOP_LEVEL_CALL) { - if (CallResolverUtil.hasReturnTypeDependentOnNotInferredParams(results.getResultingCall())) { - return null; - } + ResolvedCallImpl callToComplete = results.getResultingCall().getResolvedCallToComplete(); + if (CallResolverUtil.hasReturnTypeDependentOnNotInferredParams(callToComplete)) return null; + + // Expected type mismatch was reported before as 'TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH' + ConstraintSystem constraintSystem = callToComplete.getConstraintSystem(); + if (constraintSystem != null && constraintSystem.hasExpectedTypeMismatch()) return null; } + return results.isSingleResult() ? results.getResultingCall() : null; } result[0] = false; @@ -169,8 +175,8 @@ public class CallExpressionResolver { @Nullable private JetType getVariableType(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverValue receiver, - @Nullable ASTNode callOperationNode, @NotNull ResolutionContext context, @NotNull boolean[] result) { - + @Nullable ASTNode callOperationNode, @NotNull ResolutionContext context, @NotNull boolean[] result + ) { TemporaryBindingTrace traceForVariable = TemporaryBindingTrace.create( context.trace, "trace to resolve as local variable or property", nameExpression); CallResolver callResolver = expressionTypingServices.getCallResolver(); @@ -207,8 +213,8 @@ public class CallExpressionResolver { @NotNull public JetTypeInfo getSimpleNameExpressionTypeInfo(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverValue receiver, - @Nullable ASTNode callOperationNode, @NotNull ResolutionContext context) { - + @Nullable ASTNode callOperationNode, @NotNull ResolutionContext context + ) { boolean[] result = new boolean[1]; TemporaryBindingTrace traceForVariable = TemporaryBindingTrace.create(context.trace, "trace to resolve as variable", nameExpression); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index 689564cd1be..ef8755cc60c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -307,11 +307,10 @@ public class CallResolver { @NotNull OverloadResolutionResults results, @NotNull TracingStrategy tracing ) { - if (results.getResultCode() != OverloadResolutionResults.Code.INCOMPLETE_TYPE_INFERENCE) return; - - //todo[ResolvedCallImpl] get rid of instanceof & cast - if (!results.isSingleResult() || !(results.getResultingCall() instanceof ResolvedCallImpl)) { - argumentTypeResolver.checkTypesWithNoCallee(context, RESOLVE_FUNCTION_ARGUMENTS); + if (!results.isSingleResult()) { + if (results.getResultCode() == OverloadResolutionResults.Code.INCOMPLETE_TYPE_INFERENCE) { + argumentTypeResolver.checkTypesWithNoCallee(context, RESOLVE_FUNCTION_ARGUMENTS); + } return; } CallCandidateResolutionContext candidateContext = CallCandidateResolutionContext.createForCallBeingAnalyzed( diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java index 68444b9e7e3..853d51aac49 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java @@ -106,7 +106,9 @@ public class CallResolverUtil { return new JetTypeImpl(type.getAnnotations(), type.getConstructor(), type.isNullable(), newArguments, type.getMemberScope()); } - public static boolean hasReturnTypeDependentOnNotInferredParams(@NotNull ResolvedCall resolvedCall) { + public static boolean hasReturnTypeDependentOnNotInferredParams( + @NotNull ResolvedCallImpl resolvedCall + ) { //todo[ResolvedCallImpl] if (!(resolvedCall instanceof ResolvedCallImpl)) return false; ResolvedCallImpl call = (ResolvedCallImpl) resolvedCall; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java index d8bc8ae38bb..041ee1e7b06 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java @@ -197,9 +197,8 @@ public class CandidateResolver { CallCandidateResolutionContext context ) { ResolvedCallImpl resolvedCall = context.candidateCall; - assert resolvedCall.hasIncompleteTypeParameters(); ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem(); - assert constraintSystem != null; + if (!resolvedCall.hasIncompleteTypeParameters() || constraintSystem == null) return; // constraints for function literals // Value parameters @@ -237,11 +236,10 @@ public class CandidateResolver { List argumentTypes = checkValueArgumentTypes(context, resolvedCall, context.trace, RESOLVE_FUNCTION_ARGUMENTS).argumentTypes; JetType receiverType = resolvedCall.getReceiverArgument().exists() ? resolvedCall.getReceiverArgument().getType() : null; - context.tracing.typeInferenceFailed(context.trace, - InferenceErrorData - .create(descriptor, constraintSystem, argumentTypes, receiverType, - context.expectedType), - constraintSystemWithoutExpectedTypeConstraint); + InferenceErrorData.ExtendedInferenceErrorData errorData = InferenceErrorData + .create(descriptor, constraintSystem, argumentTypes, receiverType, context.expectedType); + + context.tracing.typeInferenceFailed(context.trace, errorData, constraintSystemWithoutExpectedTypeConstraint); resolvedCall.addStatus(ResolutionStatus.OTHER_ERROR); return; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.java index 8979dfc5ee1..7ede4ce476e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.java @@ -22,27 +22,37 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure; -import org.jetbrains.jet.lang.resolve.calls.inference.TypeConstraintsImpl.ConstraintKind; +import org.jetbrains.jet.lang.types.checker.TypingConstraints; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.*; -import static org.jetbrains.jet.lang.resolve.calls.inference.TypeConstraintsImpl.ConstraintKind.*; -import static org.jetbrains.jet.lang.types.Variance.*; +import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.EQUAL; +import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.SUB_TYPE; +import static org.jetbrains.jet.lang.resolve.calls.inference.TypeConstraintsImpl.BoundKind; +import static org.jetbrains.jet.lang.resolve.calls.inference.TypeConstraintsImpl.BoundKind.*; public class ConstraintSystemImpl implements ConstraintSystem { + public static enum ConstraintKind { + SUB_TYPE, EQUAL + } + private final Map typeParameterConstraints = Maps.newLinkedHashMap(); private final Set errorConstraintPositions = Sets.newHashSet(); private final TypeSubstitutor resultingSubstitutor; private final TypeSubstitutor currentSubstitutor; private boolean hasErrorInConstrainingTypes; + private boolean hasExpectedTypeMismatch; public ConstraintSystemImpl() { this.resultingSubstitutor = createTypeSubstitutorWithDefaultForUnknownTypeParameter(new TypeProjection(CANT_INFER)); @@ -58,7 +68,7 @@ public class ConstraintSystemImpl implements ConstraintSystem { TypeParameterDescriptor descriptor = (TypeParameterDescriptor) declarationDescriptor; JetType value = ConstraintsUtil.getValue(getTypeConstraints(descriptor)); - if (value != null && !TypeUtils.dependsOnTypeParameterConstructors(value, Collections.singleton( + if (value != null && !TypeUtils.dependsOnTypeConstructors(value, Collections.singleton( DONT_CARE.getConstructor()))) { return new TypeProjection(value); } @@ -93,7 +103,12 @@ public class ConstraintSystemImpl implements ConstraintSystem { @Override public boolean hasExpectedTypeMismatch() { - return errorConstraintPositions.size() == 1 && errorConstraintPositions.contains(ConstraintPosition.EXPECTED_TYPE_POSITION); + return hasExpectedTypeMismatch + || (errorConstraintPositions.size() == 1 && errorConstraintPositions.contains(ConstraintPosition.EXPECTED_TYPE_POSITION)); + } + + public void setHasExpectedTypeMismatch() { + hasExpectedTypeMismatch = true; } @Override @@ -142,7 +157,7 @@ public class ConstraintSystemImpl implements ConstraintSystem { @NotNull JetType subjectType, @NotNull ConstraintPosition constraintPosition ) { - addConstraint(SUPER_TYPE, subjectType, constrainingType, constraintPosition); + addConstraint(SUB_TYPE, subjectType, constrainingType, constraintPosition); } @Override @@ -151,34 +166,82 @@ public class ConstraintSystemImpl implements ConstraintSystem { @NotNull JetType subjectType, @NotNull ConstraintPosition constraintPosition ) { - addConstraint(SUB_TYPE, subjectType, constrainingType, constraintPosition); + addConstraint(SUB_TYPE, constrainingType, subjectType, constraintPosition); } - private void addConstraint(@NotNull ConstraintKind constraintKind, - @NotNull JetType subjectType, - @Nullable JetType constrainingType, - @NotNull ConstraintPosition constraintPosition) { + private void addConstraint( + @NotNull ConstraintKind constraintKind, + @Nullable JetType subType, + @Nullable JetType superType, + @NotNull final ConstraintPosition constraintPosition + ) { + TypeCheckingProcedure typeCheckingProcedure = new TypeCheckingProcedure(new TypingConstraints() { + @Override + public boolean assertEqualTypes( + @NotNull JetType a, @NotNull JetType b, @NotNull TypeCheckingProcedure typeCheckingProcedure + ) { + doAddConstraint(EQUAL, a, b, constraintPosition, typeCheckingProcedure); + return true; - if (constrainingType == TypeUtils.NO_EXPECTED_TYPE - || constrainingType == DONT_CARE - || constrainingType == CANT_INFER) { - return; + } + + @Override + public boolean assertEqualTypeConstructors( + @NotNull TypeConstructor a, @NotNull TypeConstructor b + ) { + throw new IllegalStateException("'assertEqualTypeConstructors' shouldn't be invoked inside 'isSubtypeOf'"); + } + + @Override + public boolean assertSubtype( + @NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeCheckingProcedure typeCheckingProcedure + ) { + doAddConstraint(SUB_TYPE, subtype, supertype, constraintPosition, typeCheckingProcedure); + return true; + } + + @Override + public boolean noCorrespondingSupertype( + @NotNull JetType subtype, @NotNull JetType supertype + ) { + errorConstraintPositions.add(constraintPosition); + return true; + } + }); + doAddConstraint(constraintKind, subType, superType, constraintPosition, typeCheckingProcedure); + } + + private boolean isErrorOrSpecialType(@Nullable JetType type) { + if (type == TypeUtils.NO_EXPECTED_TYPE + || type == DONT_CARE + || type == CANT_INFER) { + return true; } - if (constrainingType == null || (ErrorUtils.isErrorType(constrainingType) && constrainingType != PLACEHOLDER_FUNCTION_TYPE)) { + if (type == null || ((ErrorUtils.isErrorType(type) && type != PLACEHOLDER_FUNCTION_TYPE))) { hasErrorInConstrainingTypes = true; - return; + return true; } + return false; + } - assert subjectType != TypeUtils.NO_EXPECTED_TYPE : "Subject type shouldn't be NO_EXPECTED_TYPE (in position " + constraintPosition + " )"; - if (ErrorUtils.isErrorType(subjectType)) return; + private void doAddConstraint( + @NotNull ConstraintKind constraintKind, + @Nullable JetType subType, + @Nullable JetType superType, + @NotNull ConstraintPosition constraintPosition, + @NotNull TypeCheckingProcedure typeCheckingProcedure + ) { - DeclarationDescriptor subjectTypeDescriptor = subjectType.getConstructor().getDeclarationDescriptor(); + if (isErrorOrSpecialType(subType) || isErrorOrSpecialType(superType)) return; + assert subType != null && superType != null; + + assert superType != PLACEHOLDER_FUNCTION_TYPE : "The type for " + constraintPosition + " shouldn't be a placeholder for function type"; KotlinBuiltIns kotlinBuiltIns = KotlinBuiltIns.getInstance(); - if (constrainingType == PLACEHOLDER_FUNCTION_TYPE) { - if (!kotlinBuiltIns.isFunctionOrExtensionFunctionType(subjectType)) { - if (subjectTypeDescriptor instanceof TypeParameterDescriptor && typeParameterConstraints.get(subjectTypeDescriptor) != null) { + if (subType == PLACEHOLDER_FUNCTION_TYPE) { + if (!kotlinBuiltIns.isFunctionOrExtensionFunctionType(superType)) { + if (isMyTypeVariable(superType)) { // a constraint binds type parameter and any function type, so there is no new info and no error return; } @@ -191,159 +254,44 @@ public class ConstraintSystemImpl implements ConstraintSystem { // function literal without declaring receiver type { x -> ... } // can be considered as extension function if one is expected // (special type constructor for function/ extension function should be introduced like PLACEHOLDER_FUNCTION_TYPE) - if (constraintKind == SUB_TYPE && kotlinBuiltIns.isFunctionType(constrainingType) && kotlinBuiltIns.isExtensionFunctionType(subjectType)) { - constrainingType = createCorrespondingExtensionFunctionType(constrainingType, DONT_CARE); + if (constraintKind == SUB_TYPE && kotlinBuiltIns.isFunctionType(subType) && kotlinBuiltIns.isExtensionFunctionType(superType)) { + subType = createCorrespondingExtensionFunctionType(subType, DONT_CARE); } - DeclarationDescriptor constrainingTypeDescriptor = constrainingType.getConstructor().getDeclarationDescriptor(); + // can be equal for the recursive invocations: + // fun foo(i: Int) : T { ... return foo(i); } => T <: T + if (subType == superType) return; - if (subjectTypeDescriptor instanceof TypeParameterDescriptor) { - TypeParameterDescriptor typeParameter = (TypeParameterDescriptor) subjectTypeDescriptor; - TypeConstraintsImpl typeConstraints = typeParameterConstraints.get(typeParameter); - if (typeConstraints != null) { - if (TypeUtils.dependsOnTypeParameterConstructors(constrainingType, Collections.singleton(DONT_CARE.getConstructor()))) { - return; - } - if (subjectType.isNullable() && constrainingType.isNullable()) { - constrainingType = TypeUtils.makeNotNullable(constrainingType); - } - typeConstraints.addBound(constraintKind, constrainingType); - return; - } - } - if (constrainingTypeDescriptor instanceof TypeParameterDescriptor) { - assert typeParameterConstraints.get(constrainingTypeDescriptor) == null : "Constraining type contains type variable " + constrainingTypeDescriptor.getName(); - } - if (constraintKind == SUB_TYPE && kotlinBuiltIns.isNothingOrNullableNothing(constrainingType)) { - // following constraints are always true: - // 'Nothing' is a subtype of any type - if (!constrainingType.isNullable()) return; - // 'Nothing?' is a subtype of nullable type - if (subjectType.isNullable()) return; - } - if (!(constrainingTypeDescriptor instanceof ClassDescriptor) || !(subjectTypeDescriptor instanceof ClassDescriptor)) { - errorConstraintPositions.add(constraintPosition); + assert !isMyTypeVariable(subType) || !isMyTypeVariable(superType) : + "The constraint shouldn't contain different type variables on both sides: " + subType + " <: " + superType; + + + if (isMyTypeVariable(subType)) { + generateTypeParameterConstraint(subType, superType, constraintKind == SUB_TYPE ? UPPER_BOUND : EXACT_BOUND); return; } - switch (constraintKind) { - case SUB_TYPE: { - if (kotlinBuiltIns.isNothingOrNullableNothing(constrainingType)) break; - JetType correspondingSupertype = TypeCheckingProcedure.findCorrespondingSupertype(constrainingType, subjectType); - if (correspondingSupertype != null) { - constrainingType = correspondingSupertype; - } - break; - } - case SUPER_TYPE: { - if (kotlinBuiltIns.isNothingOrNullableNothing(subjectType)) break; - JetType correspondingSupertype = TypeCheckingProcedure.findCorrespondingSupertype(subjectType, constrainingType); - if (correspondingSupertype != null) { - subjectType = correspondingSupertype; - } - } - case EQUAL: //nothing - } - if (constrainingType.getConstructor() != subjectType.getConstructor()) { - errorConstraintPositions.add(constraintPosition); + if (isMyTypeVariable(superType)) { + generateTypeParameterConstraint(superType, subType, constraintKind == SUB_TYPE ? LOWER_BOUND : EXACT_BOUND); return; } - TypeConstructor typeConstructor = subjectType.getConstructor(); - List subjectArguments = subjectType.getArguments(); - List constrainingArguments = constrainingType.getArguments(); - List parameters = typeConstructor.getParameters(); - for (int i = 0; i < subjectArguments.size(); i++) { - Variance typeParameterVariance = parameters.get(i).getVariance(); - TypeProjection subjectArgument = subjectArguments.get(i); - TypeProjection constrainingArgument = constrainingArguments.get(i); - - ConstraintKind typeParameterConstraintKind = getTypeParameterConstraintKind(typeParameterVariance, - subjectArgument, constrainingArgument, constraintKind); - - addConstraint(typeParameterConstraintKind, subjectArgument.getType(), constrainingArgument.getType(), constraintPosition); - } + // if superType is nullable and subType is not nullable, unsafe call error will be generated later, + // but constraint system should be solved anyway + typeCheckingProcedure.isSubtypeOf(TypeUtils.makeNotNullable(subType), TypeUtils.makeNotNullable(superType)); } - /** - * Determines what constraint (supertype, subtype or equal) should be generated for type parameter {@code T} in a constraint like (in this example subtype one):
- * {@code MyClass <: MyClass}, where {@code MyClass} is declared.
- * - * The parameters description is given according to the example above. - * @param typeParameterVariance declared variance of T - * @param subjectTypeProjection {@code in/out/- A} - * @param constrainingTypeProjection {@code in/out/- B} - * @param upperConstraintKind kind of the constraint {@code MyClass<...A> <: MyClass<...B>} (subtype in this example). - * @return kind of constraint to be generated: {@code A <: B} (subtype), {@code A >: B} (supertype) or {@code A = B} (equal). - */ - @NotNull - private static ConstraintKind getTypeParameterConstraintKind( - @NotNull Variance typeParameterVariance, - @NotNull TypeProjection subjectTypeProjection, - @NotNull TypeProjection constrainingTypeProjection, - @NotNull ConstraintKind upperConstraintKind + private void generateTypeParameterConstraint( + @NotNull JetType parameterType, + @NotNull JetType constrainingType, + @NotNull BoundKind boundKind ) { - // If variance of type parameter is non-trivial, it should be taken into consideration to infer result constraint type. - // Otherwise when type parameter declared as INVARIANT, there might be non-trivial use-site variance of a supertype. - // - // Example: Let class MyClass is declared. - // - // If super type has 'out' projection: - // MyClass <: MyClass, - // then constraint A <: B can be generated. - // - // If super type has 'in' projection: - // MyClass <: MyClass, - // then constraint A >: B can be generated. - // - // Otherwise constraint A = B should be generated. + TypeConstraintsImpl typeConstraints = getTypeConstraints(parameterType); + assert typeConstraints != null : "constraint should be generated only for type variables"; - Variance varianceForTypeParameter; - if (typeParameterVariance != INVARIANT) { - varianceForTypeParameter = typeParameterVariance; + if (parameterType.isNullable()) { + // For parameter type T constraint T? <: Int? should transform to T <: Int + constrainingType = TypeUtils.makeNotNullable(constrainingType); } - else if (upperConstraintKind == SUPER_TYPE) { - varianceForTypeParameter = constrainingTypeProjection.getProjectionKind(); - } - else if (upperConstraintKind == SUB_TYPE) { - varianceForTypeParameter = subjectTypeProjection.getProjectionKind(); - } - else { - varianceForTypeParameter = INVARIANT; - } - - return getTypeParameterConstraintKind(varianceForTypeParameter, upperConstraintKind); - } - - /** - * Let class {@code MyClass} is declared.

- * - * If upperConstraintKind is SUPER_TYPE: - * {@code MyClass <: MyClass},
- * then constraints {@code A = D, B <: E, C >: F} are generated.

- * - * If upperConstraintKind is SUB_TYPE: - * {@code MyClass >: MyClass},
- * then constraints {@code A = D, B >: E, C <: F} are generated.

- * - * If upperConstraintKind is EQUAL: - * {@code MyClass = MyClass},
- * then equality constraints {@code A = D, B = E, C = F} are generated.

- * - * Method getTypeParameterConstraintKind gets upperConstraintKind and variance of type parameter - * (INVARIANT for T, OUT_VARIANCE for R in example above) and returns kind of constraint for corresponding type parameter. - */ - @NotNull - private static ConstraintKind getTypeParameterConstraintKind( - @NotNull Variance typeParameterVariance, - @NotNull ConstraintKind upperConstraintKind - ) { - if (upperConstraintKind == EQUAL || typeParameterVariance == INVARIANT) { - return EQUAL; - } - if ((upperConstraintKind == SUB_TYPE && typeParameterVariance == OUT_VARIANCE) || - (upperConstraintKind == SUPER_TYPE && typeParameterVariance == IN_VARIANCE)) { - return SUB_TYPE; - } - return SUPER_TYPE; + typeConstraints.addBound(boundKind, constrainingType); } public void processDeclaredBoundConstraints() { @@ -371,6 +319,20 @@ public class ConstraintSystemImpl implements ConstraintSystem { return typeParameterConstraints.get(typeVariable); } + @Nullable + private TypeConstraintsImpl getTypeConstraints(@NotNull JetType type) { + ClassifierDescriptor parameterDescriptor = type.getConstructor().getDeclarationDescriptor(); + if (parameterDescriptor instanceof TypeParameterDescriptor) { + return typeParameterConstraints.get(parameterDescriptor); + } + return null; + } + + private boolean isMyTypeVariable(@NotNull JetType type) { + ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); + return descriptor instanceof TypeParameterDescriptor && typeParameterConstraints.get(descriptor) != null; + } + @Override public boolean isSuccessful() { return !hasContradiction() && !hasUnknownParameters(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeConstraintsImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeConstraintsImpl.java index bcab792c4ac..785de5a6abe 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeConstraintsImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeConstraintsImpl.java @@ -39,15 +39,15 @@ public class TypeConstraintsImpl implements TypeConstraints { return varianceOfPosition; } - public void addBound(@NotNull ConstraintKind constraintKind, @NotNull JetType type) { - switch (constraintKind) { - case SUB_TYPE: + public void addBound(@NotNull BoundKind boundKind, @NotNull JetType type) { + switch (boundKind) { + case LOWER_BOUND: lowerBounds.add(type); break; - case SUPER_TYPE: + case UPPER_BOUND: upperBounds.add(type); break; - case EQUAL: + case EXACT_BOUND: exactBounds.add(type); } } @@ -89,7 +89,7 @@ public class TypeConstraintsImpl implements TypeConstraints { return typeConstraints; } - public static enum ConstraintKind { - SUPER_TYPE, SUB_TYPE, EQUAL + public static enum BoundKind { + LOWER_BOUND, UPPER_BOUND, EXACT_BOUND } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyImpl.java index 70161a14d65..eef28e3d959 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyImpl.java @@ -25,6 +25,7 @@ import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem; +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl; import org.jetbrains.jet.lang.resolve.calls.inference.InferenceErrorData; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace; import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall; @@ -221,6 +222,10 @@ public class TracingStrategyImpl implements TracingStrategy { } assert data.expectedType != null; trace.report(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.on(reference, returnType, data.expectedType)); + //todo[ConstraintSystemImpl] + if (constraintSystem instanceof ConstraintSystemImpl) { + ((ConstraintSystemImpl) constraintSystem).setHasExpectedTypeMismatch(); + } } else if (constraintSystem.hasTypeConstructorMismatch()) { trace.report(TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH.on(reference, data)); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java index 1131672cb3f..f4c7c557206 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java @@ -465,7 +465,7 @@ public class TypeUtils { } public static boolean dependsOnTypeParameters(@NotNull JetType type, @NotNull Collection typeParameters) { - return dependsOnTypeParameterConstructors(type, Collections2 + return dependsOnTypeConstructors(type, Collections2 .transform(typeParameters, new Function() { @Override public TypeConstructor apply(@Nullable TypeParameterDescriptor typeParameterDescriptor) { @@ -475,10 +475,10 @@ public class TypeUtils { })); } - public static boolean dependsOnTypeParameterConstructors(@NotNull JetType type, @NotNull Collection typeParameterConstructors) { + public static boolean dependsOnTypeConstructors(@NotNull JetType type, @NotNull Collection typeParameterConstructors) { if (typeParameterConstructors.contains(type.getConstructor())) return true; for (TypeProjection typeProjection : type.getArguments()) { - if (dependsOnTypeParameterConstructors(typeProjection.getType(), typeParameterConstructors)) { + if (dependsOnTypeConstructors(typeProjection.getType(), typeParameterConstructors)) { return true; } } diff --git a/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/noTypeParamsInReturnType.kt b/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/noTypeParamsInReturnType.kt new file mode 100644 index 00000000000..653cbeefbfe --- /dev/null +++ b/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/noTypeParamsInReturnType.kt @@ -0,0 +1,10 @@ +package b + +fun foo(map: Map) : R = throw Exception() + +fun getMap() : Map = throw Exception() + +fun bar123() { + foo(getMap( +} + diff --git a/compiler/testData/diagnostics/tests/inference/dependantOnVariance.kt b/compiler/testData/diagnostics/tests/inference/dependantOnVariance.kt index 21db1a85465..85b3a964a63 100644 --- a/compiler/testData/diagnostics/tests/inference/dependantOnVariance.kt +++ b/compiler/testData/diagnostics/tests/inference/dependantOnVariance.kt @@ -28,7 +28,7 @@ fun test1(int: Int, any: Any) { val a7 : MyList = getMyList(int) val a8 : MyList = getMyListToReadFrom(int) - val a9 : MyList = getMyListToReadFrom(int) + val a9 : MyList = getMyListToReadFrom(int) val a10 : MyList = getMyList(any) val a11 : MyList = getMyList(any) @@ -58,9 +58,9 @@ fun test1(int: Int, any: Any) { writeToMyList(getMyListToWriteTo(any), int) writeToMyList(getMyListToWriteTo(int), any) - readFromMyList(getMyListToWriteTo(any), any) + readFromMyList(getMyListToWriteTo(any), any) - writeToMyList(getMyListToReadFrom(any), any) + writeToMyList(getMyListToReadFrom(any), any) use(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13) } diff --git a/compiler/testData/diagnostics/tests/inference/regressions/compareBy.kt b/compiler/testData/diagnostics/tests/inference/regressions/compareBy.kt new file mode 100644 index 00000000000..50a113db324 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/regressions/compareBy.kt @@ -0,0 +1,9 @@ +class Item(val name: String, val rating: Int): Comparable { + public override fun compareTo(other: Item): Int { + return compareBy(this, other, { rating }, { name }) + } +} + +// from standard library +inline fun compareBy(a: T?, b: T?, + vararg functions: T.() -> Comparable<*>?): Int = throw Exception() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt2838.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt2838.kt index 62b6addd8c6..c815e3829ce 100644 --- a/compiler/testData/diagnostics/tests/inference/regressions/kt2838.kt +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt2838.kt @@ -6,7 +6,7 @@ fun bar(a: T, b: Map) = b.get(a) fun test(a: Int) { foo(a, null) - bar(a, null) + bar(a, null) } fun test1(a: Int) { foo(a, throw Exception()) diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 6f1d9769d87..460b02de3f1 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -2007,6 +2007,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/namedFun.kt"); } + @TestMetadata("noTypeParamsInReturnType.kt") + public void testNoTypeParamsInReturnType() throws Exception { + doTest("compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/noTypeParamsInReturnType.kt"); + } + @TestMetadata("typeReferenceError.kt") public void testTypeReferenceError() throws Exception { doTest("compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/typeReferenceError.kt"); @@ -2168,6 +2173,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/inference/regressions"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("compareBy.kt") + public void testCompareBy() throws Exception { + doTest("compiler/testData/diagnostics/tests/inference/regressions/compareBy.kt"); + } + @TestMetadata("kt1029.kt") public void testKt1029() throws Exception { doTest("compiler/testData/diagnostics/tests/inference/regressions/kt1029.kt");