type inference errors improvement

if constraint system without expected type was successful,
expected type mismatch error should be generated (instead of conflicting substitutions error)
 #KT-731 fixed
This commit is contained in:
Svetlana Isakova
2012-07-31 20:25:32 +04:00
parent 077f0084bd
commit 4e0a9f2af6
10 changed files with 97 additions and 43 deletions
@@ -343,7 +343,8 @@ public interface Errors {
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_UPPER_BOUND_VIOLATED = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_UPPER_BOUND_VIOLATED = DiagnosticFactory1.create(ERROR);
DiagnosticFactory2<PsiElement, JetType, JetType> TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH = DiagnosticFactory2.create(ERROR); DiagnosticFactory2<PsiElement, JetType, JetType> TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH = DiagnosticFactory2.create(ERROR);
Collection<AbstractDiagnosticFactory> TYPE_INFERENCE_ERRORS = Lists.<AbstractDiagnosticFactory>newArrayList(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER, Collection<AbstractDiagnosticFactory> TYPE_INFERENCE_ERRORS = Lists.<AbstractDiagnosticFactory>newArrayList(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER,
TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS, TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH, TYPE_INFERENCE_UPPER_BOUND_VIOLATED); TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS, TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH, TYPE_INFERENCE_UPPER_BOUND_VIOLATED,
TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH);
DiagnosticFactory1<JetElement, Integer> WRONG_NUMBER_OF_TYPE_ARGUMENTS = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<JetElement, Integer> WRONG_NUMBER_OF_TYPE_ARGUMENTS = DiagnosticFactory1.create(ERROR);
@@ -348,9 +348,6 @@ public class CallResolver {
ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem(); ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
assert constraintSystem != null; assert constraintSystem != null;
constraintSystem.addSubtypingConstraint(descriptor.getReturnType(), context.expectedType,
ConstraintPosition.EXPECTED_TYPE_POSITION);
TypeSubstitutor substituteDontCare = ConstraintSystemWithPriorities TypeSubstitutor substituteDontCare = ConstraintSystemWithPriorities
.makeConstantSubstitutor(resolvedCall.getCandidateDescriptor().getTypeParameters(), ConstraintSystemImpl.DONT_CARE); .makeConstantSubstitutor(resolvedCall.getCandidateDescriptor().getTypeParameters(), ConstraintSystemImpl.DONT_CARE);
@@ -375,22 +372,27 @@ public class CallResolver {
} }
} }
ConstraintSystem constraintSystemWithoutExpectedTypeConstraint = constraintSystem.copy();
constraintSystem.addSubtypingConstraint(descriptor.getReturnType(), context.expectedType,
ConstraintPosition.EXPECTED_TYPE_POSITION);
if (!constraintSystem.isSuccessful()) { if (!constraintSystem.isSuccessful()) {
if (constraintSystemWithoutExpectedTypeConstraint.isSuccessful()) {
resolvedCall.setResultingSubstitutor(constraintSystemWithoutExpectedTypeConstraint.getResultingSubstitutor());
}
List<JetType> argumentTypes = checkValueArgumentTypes(context, resolvedCall, context.trace).argumentTypes; List<JetType> argumentTypes = checkValueArgumentTypes(context, resolvedCall, context.trace).argumentTypes;
JetType receiverType = resolvedCall.getReceiverArgument().exists() ? resolvedCall.getReceiverArgument().getType() : null; JetType receiverType = resolvedCall.getReceiverArgument().exists() ? resolvedCall.getReceiverArgument().getType() : null;
tracing.typeInferenceFailed(context.trace, tracing.typeInferenceFailed(context.trace,
InferenceErrorData.create(descriptor, constraintSystem, argumentTypes, receiverType, context.expectedType)); InferenceErrorData
.create(descriptor, constraintSystem, argumentTypes, receiverType, context.expectedType),
constraintSystemWithoutExpectedTypeConstraint);
resolvedCall.addStatus(ResolutionStatus.TYPE_INFERENCE_ERROR); resolvedCall.addStatus(ResolutionStatus.TYPE_INFERENCE_ERROR);
failed.add(resolvedCall); failed.add(resolvedCall);
return; return;
} }
D substitute = (D) descriptor.substitute(constraintSystem.getResultingSubstitutor()); resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
assert substitute != null;
replaceValueParametersWithSubstitutedOnes(resolvedCall, substitute);
resolvedCall.setResultingDescriptor(substitute); //replacement
// Here we type check the arguments with inferred types expected // Here we type check the arguments with inferred types expected
checkValueArgumentTypes(context, resolvedCall, context.trace); checkValueArgumentTypes(context, resolvedCall, context.trace);
@@ -670,10 +672,7 @@ public class CallResolver {
Map<TypeConstructor, TypeProjection> Map<TypeConstructor, TypeProjection>
substitutionContext = FunctionDescriptorUtil.createSubstitutionContext((FunctionDescriptor)candidate, typeArguments); substitutionContext = FunctionDescriptorUtil.createSubstitutionContext((FunctionDescriptor)candidate, typeArguments);
D substitutedDescriptor = (D) candidate.substitute(TypeSubstitutor.create(substitutionContext)); candidateCall.setResultingSubstitutor(TypeSubstitutor.create(substitutionContext));
candidateCall.setResultingDescriptor(substitutedDescriptor);
replaceValueParametersWithSubstitutedOnes(candidateCall, substitutedDescriptor);
List<TypeParameterDescriptor> typeParameters = candidateCall.getCandidateDescriptor().getTypeParameters(); List<TypeParameterDescriptor> typeParameters = candidateCall.getCandidateDescriptor().getTypeParameters();
for (int i = 0; i < typeParameters.size(); i++) { for (int i = 0; i < typeParameters.size(); i++) {
@@ -756,14 +755,14 @@ public class CallResolver {
ConstraintPosition.RECEIVER_POSITION); ConstraintPosition.RECEIVER_POSITION);
} }
ConstraintSystem constraintBuilderWithRightTypeParameters = constraintsSystem.replaceTypeVariables(new Function<TypeParameterDescriptor, TypeParameterDescriptor>() { ConstraintSystem constraintSystemWithRightTypeParameters = constraintsSystem.replaceTypeVariables(new Function<TypeParameterDescriptor, TypeParameterDescriptor>() {
@Override @Override
public TypeParameterDescriptor apply(@Nullable TypeParameterDescriptor typeParameterDescriptor) { public TypeParameterDescriptor apply(@Nullable TypeParameterDescriptor typeParameterDescriptor) {
assert typeParameterDescriptor != null; assert typeParameterDescriptor != null;
return candidate.getTypeParameters().get(typeParameterDescriptor.getIndex()); return candidate.getTypeParameters().get(typeParameterDescriptor.getIndex());
} }
}); });
candidateCall.setConstraintSystem(constraintBuilderWithRightTypeParameters); candidateCall.setConstraintSystem(constraintSystemWithRightTypeParameters);
// Solution // Solution
@@ -777,7 +776,8 @@ public class CallResolver {
List<JetType> argumentTypes = checkingResult.argumentTypes; List<JetType> argumentTypes = checkingResult.argumentTypes;
JetType receiverType = candidateCall.getReceiverArgument().exists() ? candidateCall.getReceiverArgument().getType() : null; JetType receiverType = candidateCall.getReceiverArgument().exists() ? candidateCall.getReceiverArgument().getType() : null;
context.tracing.typeInferenceFailed(context.trace, context.tracing.typeInferenceFailed(context.trace,
InferenceErrorData.create(candidate, constraintBuilderWithRightTypeParameters, argumentTypes, receiverType, context.expectedType)); InferenceErrorData.create(candidate, constraintSystemWithRightTypeParameters, argumentTypes, receiverType, context.expectedType),
constraintSystemWithRightTypeParameters);
return TYPE_INFERENCE_ERROR.combine(argumentsStatus); return TYPE_INFERENCE_ERROR.combine(argumentsStatus);
} }
} }
@@ -852,23 +852,7 @@ public class CallResolver {
} }
} }
private static <D extends CallableDescriptor> void replaceValueParametersWithSubstitutedOnes(
ResolvedCallImpl<D> candidateCall, @NotNull D substitutedDescriptor) {
Map<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap = Maps.newHashMap();
for (ValueParameterDescriptor valueParameterDescriptor : substitutedDescriptor.getValueParameters()) {
parameterMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor);
}
Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = candidateCall.getValueArguments();
Map<ValueParameterDescriptor, ResolvedValueArgument> originalValueArguments = Maps.newHashMap(valueArguments);
valueArguments.clear();
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : originalValueArguments.entrySet()) {
ValueParameterDescriptor substitutedVersion = parameterMap.get(entry.getKey().getOriginal());
assert substitutedVersion != null : entry.getKey();
valueArguments.put(substitutedVersion, entry.getValue());
}
}
private <D extends CallableDescriptor, F extends D> ValueArgumentsCheckingResult checkAllValueArguments(CallResolutionContext<D, F> context) { private <D extends CallableDescriptor, F extends D> ValueArgumentsCheckingResult checkAllValueArguments(CallResolutionContext<D, F> context) {
ValueArgumentsCheckingResult checkingResult = checkValueArgumentTypes(context, context.candidateCall); ValueArgumentsCheckingResult checkingResult = checkValueArgumentTypes(context, context.candidateCall);
@@ -35,6 +35,7 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.ErrorUtils; import org.jetbrains.jet.lang.types.ErrorUtils;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.Variance;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions; import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
import org.jetbrains.jet.lexer.JetToken; import org.jetbrains.jet.lexer.JetToken;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
@@ -238,15 +239,20 @@ public class ResolutionTask<D extends CallableDescriptor, F extends D> extends R
} }
@Override @Override
public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData data) { public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData data, @NotNull ConstraintSystem systemWithoutExpectedTypeConstraint) {
ConstraintSystem constraintSystem = data.constraintSystem; ConstraintSystem constraintSystem = data.constraintSystem;
assert !constraintSystem.isSuccessful(); assert !constraintSystem.isSuccessful();
if (constraintSystem.hasErrorInConstrainingTypes()) { if (constraintSystem.hasErrorInConstrainingTypes()) {
return; return;
} }
if (constraintSystem.hasExpectedTypeMismatch()) { boolean successfulWithoutExpectedTypeConstraint = systemWithoutExpectedTypeConstraint.isSuccessful();
if (constraintSystem.hasExpectedTypeMismatch() || successfulWithoutExpectedTypeConstraint) {
JetType returnType = data.descriptor.getReturnType(); JetType returnType = data.descriptor.getReturnType();
assert returnType != null; assert returnType != null;
if (successfulWithoutExpectedTypeConstraint) {
returnType = systemWithoutExpectedTypeConstraint.getResultingSubstitutor().substitute(returnType, Variance.INVARIANT);
assert returnType != null;
}
trace.report(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.on(reference, returnType, data.expectedType)); trace.report(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.on(reference, returnType, data.expectedType));
} }
else if (constraintSystem.hasTypeConstructorMismatch()) { else if (constraintSystem.hasTypeConstructorMismatch()) {
@@ -27,6 +27,7 @@ import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem; import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -120,9 +121,22 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements ResolvedC
return resultingDescriptor == null ? candidateDescriptor : resultingDescriptor; return resultingDescriptor == null ? candidateDescriptor : resultingDescriptor;
} }
public ResolvedCallImpl<D> setResultingDescriptor(@NotNull D resultingDescriptor) { public void setResultingSubstitutor(@NotNull TypeSubstitutor substitutor) {
this.resultingDescriptor = resultingDescriptor; resultingDescriptor = (D) candidateDescriptor.substitute(substitutor);
return this; assert resultingDescriptor != null : candidateDescriptor;
Map<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap = Maps.newHashMap();
for (ValueParameterDescriptor valueParameterDescriptor : resultingDescriptor.getValueParameters()) {
parameterMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor);
}
Map<ValueParameterDescriptor, ResolvedValueArgument> originalValueArguments = Maps.newHashMap(valueArguments);
valueArguments.clear();
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : originalValueArguments.entrySet()) {
ValueParameterDescriptor substitutedVersion = parameterMap.get(entry.getKey().getOriginal());
assert substitutedVersion != null : entry.getKey();
valueArguments.put(substitutedVersion, entry.getValue());
}
} }
public void recordTypeArgument(@NotNull TypeParameterDescriptor typeParameter, @NotNull JetType typeArgument) { public void recordTypeArgument(@NotNull TypeParameterDescriptor typeParameter, @NotNull JetType typeArgument) {
@@ -22,6 +22,7 @@ import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.jet.lang.resolve.calls.inference.InferenceErrorData; import org.jetbrains.jet.lang.resolve.calls.inference.InferenceErrorData;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
@@ -84,7 +85,8 @@ import java.util.List;
public void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptor descriptor) {} public void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptor descriptor) {}
@Override @Override
public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData) {} public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData,
@NotNull ConstraintSystem systemWithoutExpectedTypeConstraint) {}
@Override @Override
public void upperBoundViolated(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData) {} public void upperBoundViolated(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData) {}
@@ -122,7 +124,8 @@ import java.util.List;
void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptor descriptor); void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptor descriptor);
void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData); void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData,
@NotNull ConstraintSystem systemWithoutExpectedTypeConstraint);
void upperBoundViolated(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData); void upperBoundViolated(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData);
} }
@@ -109,7 +109,11 @@ public class ConstraintSystemImpl implements ConstraintSystem {
@NotNull @NotNull
public ConstraintSystem copy() { public ConstraintSystem copy() {
ConstraintSystemImpl newConstraintSystem = new ConstraintSystemImpl(); ConstraintSystemImpl newConstraintSystem = new ConstraintSystemImpl();
newConstraintSystem.typeParameterConstraints.putAll(typeParameterConstraints); for (Map.Entry<TypeParameterDescriptor, TypeConstraintsImpl> entry : typeParameterConstraints.entrySet()) {
TypeParameterDescriptor typeParameter = entry.getKey();
TypeConstraintsImpl typeConstraints = entry.getValue();
newConstraintSystem.typeParameterConstraints.put(typeParameter, typeConstraints.copy());
}
newConstraintSystem.errorConstraintPositions.addAll(errorConstraintPositions); newConstraintSystem.errorConstraintPositions.addAll(errorConstraintPositions);
newConstraintSystem.hasErrorInConstrainingTypes = hasErrorInConstrainingTypes; newConstraintSystem.hasErrorInConstrainingTypes = hasErrorInConstrainingTypes;
return newConstraintSystem; return newConstraintSystem;
@@ -151,7 +151,7 @@ public class ConstraintsUtil {
return true; return true;
} }
public static boolean checkBoundsAreSatisfied(ConstraintSystem constraintSystem) { public static boolean checkBoundsAreSatisfied(@NotNull ConstraintSystem constraintSystem) {
for (TypeParameterDescriptor typeVariable : constraintSystem.getTypeVariables()) { for (TypeParameterDescriptor typeVariable : constraintSystem.getTypeVariables()) {
JetType type = getValue(constraintSystem.getTypeConstraints(typeVariable)); JetType type = getValue(constraintSystem.getTypeConstraints(typeVariable));
JetType upperBound = typeVariable.getUpperBoundsAsType(); JetType upperBound = typeVariable.getUpperBoundsAsType();
@@ -78,6 +78,20 @@ public class TypeConstraintsImpl implements TypeConstraints {
return exactBounds; return exactBounds;
} }
/*package*/ TypeConstraintsImpl copy() {
TypeConstraintsImpl typeConstraints = new TypeConstraintsImpl(varianceOfPosition);
for (JetType upperBound : upperBounds) {
typeConstraints.upperBounds.add(upperBound);
}
for (JetType lowerBound : lowerBounds) {
typeConstraints.lowerBounds.add(lowerBound);
}
for (JetType exactBound : exactBounds) {
typeConstraints.exactBounds.add(exactBound);
}
return typeConstraints;
}
public static enum ConstraintKind { public static enum ConstraintKind {
SUB_TYPE, SUPER_TYPE, EQUAL; SUB_TYPE, SUPER_TYPE, EQUAL;
@@ -0,0 +1,15 @@
package a
class A<T>(x: T) {
val p = x
}
fun <T, G> A<T>.foo(x: (T)-> G): G {
return x(this.p)
}
fun main(args: Array<String>) {
val a = A(1)
val t: String = a.<!TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>foo<!>({p -> p})
t : String
}
@@ -15,12 +15,15 @@
*/ */
package org.jetbrains.jet.checkers; package org.jetbrains.jet.checkers;
import junit.framework.Assert;
import junit.framework.Test; import junit.framework.Test;
import junit.framework.TestSuite; import junit.framework.TestSuite;
import java.io.File;
import org.jetbrains.jet.JetTestUtils; import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.test.TestMetadata; import org.jetbrains.jet.test.TestMetadata;
import java.io.File; import org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve;
/** This class is generated by {@link org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve}. DO NOT MODIFY MANUALLY */ /** This class is generated by {@link org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve}. DO NOT MODIFY MANUALLY */
public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEagerResolve { public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEagerResolve {
@@ -1362,6 +1365,16 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
doTest("compiler/testData/diagnostics/tests/inference/regressions/kt2324.kt"); doTest("compiler/testData/diagnostics/tests/inference/regressions/kt2324.kt");
} }
@TestMetadata("kt702.kt")
public void testKt702() throws Exception {
doTest("compiler/testData/diagnostics/tests/inference/regressions/kt702.kt");
}
@TestMetadata("kt731.kt")
public void testKt731() throws Exception {
doTest("compiler/testData/diagnostics/tests/inference/regressions/kt731.kt");
}
} }
public static Test innerSuite() { public static Test innerSuite() {