use TypeCheckingProcedure for generating constraints

(in ConstraintSystemImpl)
This commit is contained in:
Svetlana Isakova
2013-02-27 21:00:40 +04:00
parent 871caaaa2d
commit 0530df6f7b
13 changed files with 202 additions and 201 deletions
@@ -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<FunctionDescriptor> 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<FunctionDescriptor> 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);
@@ -307,11 +307,10 @@ public class CallResolver {
@NotNull OverloadResolutionResults<D> 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<D> candidateContext = CallCandidateResolutionContext.createForCallBeingAnalyzed(
@@ -106,7 +106,9 @@ public class CallResolverUtil {
return new JetTypeImpl(type.getAnnotations(), type.getConstructor(), type.isNullable(), newArguments, type.getMemberScope());
}
public static <D extends CallableDescriptor> boolean hasReturnTypeDependentOnNotInferredParams(@NotNull ResolvedCall<D> resolvedCall) {
public static <D extends CallableDescriptor> boolean hasReturnTypeDependentOnNotInferredParams(
@NotNull ResolvedCallImpl<D> resolvedCall
) {
//todo[ResolvedCallImpl]
if (!(resolvedCall instanceof ResolvedCallImpl)) return false;
ResolvedCallImpl call = (ResolvedCallImpl) resolvedCall;
@@ -197,9 +197,8 @@ public class CandidateResolver {
CallCandidateResolutionContext<D> context
) {
ResolvedCallImpl<D> 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<JetType> 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;
}
@@ -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<TypeParameterDescriptor, TypeConstraintsImpl> typeParameterConstraints = Maps.newLinkedHashMap();
private final Set<ConstraintPosition> 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 <T> 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<TypeProjection> subjectArguments = subjectType.getArguments();
List<TypeProjection> constrainingArguments = constrainingType.getArguments();
List<TypeParameterDescriptor> 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): <br/>
* {@code MyClass<in/out/- A> <: MyClass<in/out/- B>}, where {@code MyClass<in/out/- T>} is declared. <br/>
*
* 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<T> is declared.
//
// If super type has 'out' projection:
// MyClass<A> <: MyClass<out B>,
// then constraint A <: B can be generated.
//
// If super type has 'in' projection:
// MyClass<A> <: MyClass<in B>,
// 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<T, out R, in S>} is declared.<br/><br/>
*
* If upperConstraintKind is SUPER_TYPE:
* {@code MyClass<A, B, C> <: MyClass<D, E, F>}, <br/>
* then constraints {@code A = D, B <: E, C >: F} are generated. <br/><br/>
*
* If upperConstraintKind is SUB_TYPE:
* {@code MyClass<A, B, C> >: MyClass<D, E, F>}, <br/>
* then constraints {@code A = D, B >: E, C <: F} are generated. <br/><br/>
*
* If upperConstraintKind is EQUAL:
* {@code MyClass<A, B, C> = MyClass<D, E, F>}, <br/>
* then equality constraints {@code A = D, B = E, C = F} are generated. <br/><br/>
*
* 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();
@@ -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
}
}
@@ -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));
@@ -465,7 +465,7 @@ public class TypeUtils {
}
public static boolean dependsOnTypeParameters(@NotNull JetType type, @NotNull Collection<TypeParameterDescriptor> typeParameters) {
return dependsOnTypeParameterConstructors(type, Collections2
return dependsOnTypeConstructors(type, Collections2
.transform(typeParameters, new Function<TypeParameterDescriptor, TypeConstructor>() {
@Override
public TypeConstructor apply(@Nullable TypeParameterDescriptor typeParameterDescriptor) {
@@ -475,10 +475,10 @@ public class TypeUtils {
}));
}
public static boolean dependsOnTypeParameterConstructors(@NotNull JetType type, @NotNull Collection<TypeConstructor> typeParameterConstructors) {
public static boolean dependsOnTypeConstructors(@NotNull JetType type, @NotNull Collection<TypeConstructor> 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;
}
}
@@ -0,0 +1,10 @@
package b
fun <T, R> foo(<!UNUSED_PARAMETER!>map<!>: Map<T, R>) : R = throw Exception()
fun <F, G> getMap() : Map<F, G> = throw Exception()
fun bar123() {
<!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>foo<!>(<!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>getMap<!>(
<!SYNTAX!><!>}
@@ -28,7 +28,7 @@ fun test1(int: Int, any: Any) {
val a7 : MyList<in Any> = getMyList(int)
val a8 : MyList<in Any> = <!TYPE_MISMATCH!>getMyListToReadFrom<Int>(int)<!>
val a9 : MyList<in Any> = <!TYPE_MISMATCH!>getMyListToReadFrom(int)<!>
val a9 : MyList<in Any> = <!TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>getMyListToReadFrom<!>(int)
val a10 : MyList<out Int> = <!TYPE_MISMATCH!>getMyList<Any>(any)<!>
val a11 : MyList<out Int> = <!TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>getMyList<!>(any)
@@ -58,9 +58,9 @@ fun test1(int: Int, any: Any) {
writeToMyList(getMyListToWriteTo(any), int)
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>writeToMyList<!>(getMyListToWriteTo(int), any)
readFromMyList(<!TYPE_MISMATCH!>getMyListToWriteTo(any)<!>, any)
readFromMyList(getMyListToWriteTo(any), any)
writeToMyList(<!TYPE_MISMATCH!>getMyListToReadFrom(any)<!>, any)
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>writeToMyList<!>(getMyListToReadFrom(any), any)
use(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13)
}
@@ -0,0 +1,9 @@
class Item(val name: String, val rating: Int): Comparable<Item> {
public override fun compareTo(other: Item): Int {
return compareBy(this, other, { rating }, { name })
}
}
// from standard library
inline fun <T : Any> compareBy(<!UNUSED_PARAMETER!>a<!>: T?, <!UNUSED_PARAMETER!>b<!>: T?,
vararg <!UNUSED_PARAMETER!>functions<!>: T.() -> Comparable<*>?): Int = throw Exception()
@@ -6,7 +6,7 @@ fun bar<T>(a: T, b: Map<T, String>) = b.get(a)
fun test(a: Int) {
foo(a, null)
<!TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH!>bar<!>(a, null)
bar(a, <!ERROR_COMPILE_TIME_VALUE!>null<!>)
}
fun test1(a: Int) {
<!UNREACHABLE_CODE!>foo(a, throw Exception())<!>
@@ -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");