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:
@@ -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);
|
||||
}
|
||||
|
||||
+5
-1
@@ -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;
|
||||
|
||||
+1
-1
@@ -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();
|
||||
|
||||
+14
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user