diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 0afe35d3a74..c4ad2473e0a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -343,7 +343,8 @@ public interface Errors { DiagnosticFactory1 TYPE_INFERENCE_UPPER_BOUND_VIOLATED = DiagnosticFactory1.create(ERROR); DiagnosticFactory2 TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH = DiagnosticFactory2.create(ERROR); Collection TYPE_INFERENCE_ERRORS = Lists.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 WRONG_NUMBER_OF_TYPE_ARGUMENTS = DiagnosticFactory1.create(ERROR); 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 f4ebb8673ba..2c3fc6d097d 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 @@ -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 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 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 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() { + ConstraintSystem constraintSystemWithRightTypeParameters = constraintsSystem.replaceTypeVariables(new Function() { @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 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 void replaceValueParametersWithSubstitutedOnes( - ResolvedCallImpl candidateCall, @NotNull D substitutedDescriptor) { - Map parameterMap = Maps.newHashMap(); - for (ValueParameterDescriptor valueParameterDescriptor : substitutedDescriptor.getValueParameters()) { - parameterMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor); - } - - Map valueArguments = candidateCall.getValueArguments(); - Map originalValueArguments = Maps.newHashMap(valueArguments); - valueArguments.clear(); - for (Map.Entry entry : originalValueArguments.entrySet()) { - ValueParameterDescriptor substitutedVersion = parameterMap.get(entry.getKey().getOriginal()); - assert substitutedVersion != null : entry.getKey(); - valueArguments.put(substitutedVersion, entry.getValue()); - } - } private ValueArgumentsCheckingResult checkAllValueArguments(CallResolutionContext context) { ValueArgumentsCheckingResult checkingResult = checkValueArgumentTypes(context, context.candidateCall); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java index 3565a18a2ac..ac3425dff72 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java @@ -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 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()) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCallImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCallImpl.java index 0261d475809..4ea9462eac1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCallImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCallImpl.java @@ -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 implements ResolvedC return resultingDescriptor == null ? candidateDescriptor : resultingDescriptor; } - public ResolvedCallImpl 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 parameterMap = Maps.newHashMap(); + for (ValueParameterDescriptor valueParameterDescriptor : resultingDescriptor.getValueParameters()) { + parameterMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor); + } + + Map originalValueArguments = Maps.newHashMap(valueArguments); + valueArguments.clear(); + for (Map.Entry 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) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java index bd36a80cac3..b5b60dfaf54 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java @@ -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); } 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 3ca82d3d353..5df320ed699 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 @@ -109,7 +109,11 @@ public class ConstraintSystemImpl implements ConstraintSystem { @NotNull public ConstraintSystem copy() { ConstraintSystemImpl newConstraintSystem = new ConstraintSystemImpl(); - newConstraintSystem.typeParameterConstraints.putAll(typeParameterConstraints); + for (Map.Entry 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; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintsUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintsUtil.java index ab1cd48af82..3422aeda22e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintsUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintsUtil.java @@ -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(); 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 5c6cc7ec0f4..ac4aeda95b4 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 @@ -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; diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt731.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt731.kt new file mode 100644 index 00000000000..a1eca3529c1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt731.kt @@ -0,0 +1,15 @@ +package a + +class A(x: T) { + val p = x +} + +fun A.foo(x: (T)-> G): G { + return x(this.p) +} + +fun main(args: Array) { + val a = A(1) + val t: String = a.foo({p -> p}) + t : String +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 25121a79a5f..260dc17023d 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -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() {