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);
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,
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);
@@ -348,9 +348,6 @@ public class CallResolver {
ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
assert constraintSystem != null;
constraintSystem.addSubtypingConstraint(descriptor.getReturnType(), context.expectedType,
ConstraintPosition.EXPECTED_TYPE_POSITION);
TypeSubstitutor substituteDontCare = ConstraintSystemWithPriorities
.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 (constraintSystemWithoutExpectedTypeConstraint.isSuccessful()) {
resolvedCall.setResultingSubstitutor(constraintSystemWithoutExpectedTypeConstraint.getResultingSubstitutor());
}
List<JetType> argumentTypes = checkValueArgumentTypes(context, resolvedCall, context.trace).argumentTypes;
JetType receiverType = resolvedCall.getReceiverArgument().exists() ? resolvedCall.getReceiverArgument().getType() : null;
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);
failed.add(resolvedCall);
return;
}
D substitute = (D) descriptor.substitute(constraintSystem.getResultingSubstitutor());
assert substitute != null;
replaceValueParametersWithSubstitutedOnes(resolvedCall, substitute);
resolvedCall.setResultingDescriptor(substitute); //replacement
resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
// Here we type check the arguments with inferred types expected
checkValueArgumentTypes(context, resolvedCall, context.trace);
@@ -670,10 +672,7 @@ public class CallResolver {
Map<TypeConstructor, TypeProjection>
substitutionContext = FunctionDescriptorUtil.createSubstitutionContext((FunctionDescriptor)candidate, typeArguments);
D substitutedDescriptor = (D) candidate.substitute(TypeSubstitutor.create(substitutionContext));
candidateCall.setResultingDescriptor(substitutedDescriptor);
replaceValueParametersWithSubstitutedOnes(candidateCall, substitutedDescriptor);
candidateCall.setResultingSubstitutor(TypeSubstitutor.create(substitutionContext));
List<TypeParameterDescriptor> typeParameters = candidateCall.getCandidateDescriptor().getTypeParameters();
for (int i = 0; i < typeParameters.size(); i++) {
@@ -756,14 +755,14 @@ public class CallResolver {
ConstraintPosition.RECEIVER_POSITION);
}
ConstraintSystem constraintBuilderWithRightTypeParameters = constraintsSystem.replaceTypeVariables(new Function<TypeParameterDescriptor, TypeParameterDescriptor>() {
ConstraintSystem constraintSystemWithRightTypeParameters = constraintsSystem.replaceTypeVariables(new Function<TypeParameterDescriptor, TypeParameterDescriptor>() {
@Override
public TypeParameterDescriptor apply(@Nullable TypeParameterDescriptor typeParameterDescriptor) {
assert typeParameterDescriptor != null;
return candidate.getTypeParameters().get(typeParameterDescriptor.getIndex());
}
});
candidateCall.setConstraintSystem(constraintBuilderWithRightTypeParameters);
candidateCall.setConstraintSystem(constraintSystemWithRightTypeParameters);
// Solution
@@ -777,7 +776,8 @@ public class CallResolver {
List<JetType> argumentTypes = checkingResult.argumentTypes;
JetType receiverType = candidateCall.getReceiverArgument().exists() ? candidateCall.getReceiverArgument().getType() : null;
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);
}
}
@@ -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) {
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.types.ErrorUtils;
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.lexer.JetToken;
import org.jetbrains.jet.lexer.JetTokens;
@@ -238,15 +239,20 @@ public class ResolutionTask<D extends CallableDescriptor, F extends D> extends R
}
@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;
assert !constraintSystem.isSuccessful();
if (constraintSystem.hasErrorInConstrainingTypes()) {
return;
}
if (constraintSystem.hasExpectedTypeMismatch()) {
boolean successfulWithoutExpectedTypeConstraint = systemWithoutExpectedTypeConstraint.isSuccessful();
if (constraintSystem.hasExpectedTypeMismatch() || successfulWithoutExpectedTypeConstraint) {
JetType returnType = data.descriptor.getReturnType();
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));
}
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.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
import java.util.ArrayList;
import java.util.List;
@@ -120,9 +121,22 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements ResolvedC
return resultingDescriptor == null ? candidateDescriptor : resultingDescriptor;
}
public ResolvedCallImpl<D> setResultingDescriptor(@NotNull D resultingDescriptor) {
this.resultingDescriptor = resultingDescriptor;
return this;
public void setResultingSubstitutor(@NotNull TypeSubstitutor substitutor) {
resultingDescriptor = (D) candidateDescriptor.substitute(substitutor);
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) {
@@ -22,6 +22,7 @@ import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.psi.JetExpression;
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.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
@@ -84,7 +85,8 @@ import java.util.List;
public void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptor descriptor) {}
@Override
public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData) {}
public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData,
@NotNull ConstraintSystem systemWithoutExpectedTypeConstraint) {}
@Override
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 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);
}
@@ -109,7 +109,11 @@ public class ConstraintSystemImpl implements ConstraintSystem {
@NotNull
public ConstraintSystem copy() {
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.hasErrorInConstrainingTypes = hasErrorInConstrainingTypes;
return newConstraintSystem;
@@ -151,7 +151,7 @@ public class ConstraintsUtil {
return true;
}
public static boolean checkBoundsAreSatisfied(ConstraintSystem constraintSystem) {
public static boolean checkBoundsAreSatisfied(@NotNull ConstraintSystem constraintSystem) {
for (TypeParameterDescriptor typeVariable : constraintSystem.getTypeVariables()) {
JetType type = getValue(constraintSystem.getTypeConstraints(typeVariable));
JetType upperBound = typeVariable.getUpperBoundsAsType();
@@ -78,6 +78,20 @@ public class TypeConstraintsImpl implements TypeConstraints {
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 {
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;
import junit.framework.Assert;
import junit.framework.Test;
import junit.framework.TestSuite;
import java.io.File;
import org.jetbrains.jet.JetTestUtils;
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 */
public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEagerResolve {
@@ -1362,6 +1365,16 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
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() {