use declared upper bounds in type inference (not just check them)
- simple cases supported #KT-2856 fixed
This commit is contained in:
@@ -266,7 +266,7 @@ public class Renderers {
|
||||
public static TabledDescriptorRenderer renderUpperBoundViolatedInferenceError(InferenceErrorData inferenceErrorData, TabledDescriptorRenderer result) {
|
||||
TypeParameterDescriptor typeParameterDescriptor = null;
|
||||
for (TypeParameterDescriptor typeParameter : inferenceErrorData.descriptor.getTypeParameters()) {
|
||||
if (!ConstraintsUtil.checkUpperBoundIsSatisfied(inferenceErrorData.constraintSystem, typeParameter)) {
|
||||
if (!ConstraintsUtil.checkUpperBoundIsSatisfied(inferenceErrorData.constraintSystem, typeParameter, true)) {
|
||||
typeParameterDescriptor = typeParameter;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -41,10 +41,7 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT;
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.SUPER_IS_NOT_AN_EXPRESSION;
|
||||
@@ -238,11 +235,23 @@ public class CandidateResolver {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean boundsAreSatisfied = ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, /*substituteOtherTypeParametersInBounds=*/true);
|
||||
if (!boundsAreSatisfied) {
|
||||
ConstraintSystemImpl copy = (ConstraintSystemImpl) constraintSystem.copy();
|
||||
copy.processDeclaredBoundConstraints();
|
||||
boundsAreSatisfied = copy.isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(copy, /*substituteOtherTypeParametersInBounds=*/true);
|
||||
if (boundsAreSatisfied) {
|
||||
constraintSystem = copy;
|
||||
}
|
||||
}
|
||||
if (!boundsAreSatisfied) {
|
||||
context.tracing.upperBoundViolated(resolvedCall.getTrace(), InferenceErrorData.create(resolvedCall.getCandidateDescriptor(), constraintSystem));
|
||||
}
|
||||
resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
|
||||
|
||||
// Here we type check the arguments with inferred types expected
|
||||
checkAllValueArguments(context, RESOLVE_FUNCTION_ARGUMENTS);
|
||||
|
||||
checkBounds(resolvedCall, constraintSystem, resolvedCall.getTrace(), context.tracing);
|
||||
resolvedCall.setHasUnknownTypeParameters(false);
|
||||
if (resolvedCall.getStatus() == ResolutionStatus.UNKNOWN_STATUS) {
|
||||
resolvedCall.addStatus(ResolutionStatus.SUCCESS);
|
||||
@@ -319,7 +328,7 @@ public class CandidateResolver {
|
||||
|
||||
// Solution
|
||||
boolean hasContradiction = constraintSystem.hasContradiction();
|
||||
boolean boundsAreSatisfied = ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem);
|
||||
boolean boundsAreSatisfied = ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, /*substituteOtherTypeParametersInBounds=*/false);
|
||||
if (!hasContradiction && boundsAreSatisfied) {
|
||||
candidateCall.setHasUnknownTypeParameters(true);
|
||||
return SUCCESS;
|
||||
@@ -526,19 +535,6 @@ public class CandidateResolver {
|
||||
}
|
||||
}
|
||||
|
||||
private static <D extends CallableDescriptor> void checkBounds(
|
||||
@NotNull ResolvedCallImpl<D> call,
|
||||
@NotNull ConstraintSystem constraintSystem,
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull TracingStrategy tracing
|
||||
) {
|
||||
for (TypeParameterDescriptor typeParameter : call.getCandidateDescriptor().getTypeParameters()) {
|
||||
if (!ConstraintsUtil.checkUpperBoundIsSatisfied(constraintSystem, typeParameter)) {
|
||||
tracing.upperBoundViolated(trace, InferenceErrorData.create(call.getCandidateDescriptor(), constraintSystem));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkGenericBoundsInAFunctionCall(
|
||||
@NotNull List<JetTypeProjection> jetTypeArguments,
|
||||
@NotNull List<JetType> typeArguments,
|
||||
|
||||
+1
@@ -23,6 +23,7 @@ import java.util.Map;
|
||||
public class ConstraintPosition {
|
||||
public static final ConstraintPosition RECEIVER_POSITION = new ConstraintPosition("RECEIVER_POSITION");
|
||||
public static final ConstraintPosition EXPECTED_TYPE_POSITION = new ConstraintPosition("EXPECTED_TYPE_POSITION");
|
||||
public static final ConstraintPosition BOUND_CONSTRAINT_POSITION = new ConstraintPosition("BOUND_CONSTRAINT_POSITION");
|
||||
|
||||
private static final Map<Integer, ConstraintPosition> valueParameterPositions = Maps.newHashMap();
|
||||
|
||||
|
||||
+14
-3
@@ -32,9 +32,7 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.CANT_INFER;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.DONT_CARE;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.PLACEHOLDER_FUNCTION_TYPE;
|
||||
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.*;
|
||||
|
||||
@@ -348,6 +346,19 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
||||
return SUPER_TYPE;
|
||||
}
|
||||
|
||||
public void processDeclaredBoundConstraints() {
|
||||
for (Map.Entry<TypeParameterDescriptor, TypeConstraintsImpl> entry : typeParameterConstraints.entrySet()) {
|
||||
TypeParameterDescriptor typeParameterDescriptor = entry.getKey();
|
||||
TypeConstraintsImpl typeConstraints = entry.getValue();
|
||||
for (JetType declaredUpperBound : typeParameterDescriptor.getUpperBounds()) {
|
||||
//todo order matters here
|
||||
for (JetType lowerOrExactBound : Sets.union(typeConstraints.getLowerBounds(), typeConstraints.getExactBounds())) {
|
||||
addSubtypeConstraint(lowerOrExactBound, declaredUpperBound, ConstraintPosition.BOUND_CONSTRAINT_POSITION);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<TypeParameterDescriptor> getTypeVariables() {
|
||||
|
||||
+18
-8
@@ -153,25 +153,35 @@ public class ConstraintsUtil {
|
||||
return typeParameter.getUpperBoundsAsType();
|
||||
}
|
||||
|
||||
public static boolean checkUpperBoundIsSatisfied(@NotNull ConstraintSystem constraintSystem,
|
||||
@NotNull TypeParameterDescriptor typeParameter) {
|
||||
public static boolean checkUpperBoundIsSatisfied(
|
||||
@NotNull ConstraintSystem constraintSystem,
|
||||
@NotNull TypeParameterDescriptor typeParameter,
|
||||
boolean substituteOtherTypeParametersInBound
|
||||
) {
|
||||
TypeConstraints typeConstraints = constraintSystem.getTypeConstraints(typeParameter);
|
||||
assert typeConstraints != null;
|
||||
JetType type = getValue(typeConstraints);
|
||||
JetType upperBound = typeParameter.getUpperBoundsAsType();
|
||||
JetType substitutedType = constraintSystem.getResultingSubstitutor().substitute(upperBound, Variance.INVARIANT);
|
||||
if (type == null) return true;
|
||||
for (JetType upperBound : typeParameter.getUpperBounds()) {
|
||||
if (!substituteOtherTypeParametersInBound && TypeUtils.dependsOnTypeParameters(upperBound, constraintSystem.getTypeVariables())) {
|
||||
continue;
|
||||
}
|
||||
JetType substitutedUpperBound = constraintSystem.getResultingSubstitutor().substitute(upperBound, Variance.INVARIANT);
|
||||
|
||||
if (type != null) {
|
||||
if (substitutedType == null || !JetTypeChecker.INSTANCE.isSubtypeOf(type, substitutedType)) {
|
||||
assert substitutedUpperBound != null : "We wanted to substitute projections as a result for " + typeParameter;
|
||||
if (!JetTypeChecker.INSTANCE.isSubtypeOf(type, substitutedUpperBound)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean checkBoundsAreSatisfied(@NotNull ConstraintSystem constraintSystem) {
|
||||
public static boolean checkBoundsAreSatisfied(
|
||||
@NotNull ConstraintSystem constraintSystem,
|
||||
boolean substituteOtherTypeParametersInBounds
|
||||
) {
|
||||
for (TypeParameterDescriptor typeVariable : constraintSystem.getTypeVariables()) {
|
||||
if (!checkUpperBoundIsSatisfied(constraintSystem, typeVariable)) {
|
||||
if (!checkUpperBoundIsSatisfied(constraintSystem, typeVariable, substituteOtherTypeParametersInBounds)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -251,7 +251,7 @@ public class ExpressionTypingUtils {
|
||||
}
|
||||
|
||||
constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.getType(), ConstraintPosition.RECEIVER_POSITION);
|
||||
return constraintSystem.isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem);
|
||||
return constraintSystem.isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, true);
|
||||
}
|
||||
|
||||
private static Set<Name> collectUsedTypeNames(@NotNull JetType jetType) {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
//KT-2856 Fix the getOrElse signature to be able to return any supertype of V
|
||||
package d
|
||||
|
||||
import java.util.HashMap
|
||||
|
||||
public inline fun <K,V1, V: V1> Map<K,V>.getOrElse1(key: K, defaultValue: ()-> V1) : V1 {
|
||||
if (this.containsKey(key)) {
|
||||
return this.get(key) as V
|
||||
} else {
|
||||
return defaultValue()
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val map = HashMap<Int, Int>()
|
||||
println(map.getOrElse1(2, { null })) // Error
|
||||
}
|
||||
|
||||
//from standard library
|
||||
fun println(<!UNUSED_PARAMETER!>message<!> : Any?) {}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package a
|
||||
|
||||
fun foo<V : U, U>(<!UNUSED_PARAMETER!>v<!>: V, u: U) = u
|
||||
fun bar<U, V : U>(<!UNUSED_PARAMETER!>v<!>: V, u: U) = u
|
||||
|
||||
fun test(a: Any, s: String) {
|
||||
val <!UNUSED_VARIABLE!>b<!>: Any = <!TYPE_INFERENCE_UPPER_BOUND_VIOLATED!>foo<!>(a, s) //depends on type parameter order, will be fixed in next commit
|
||||
val <!UNUSED_VARIABLE!>c<!>: Any = bar(a, s)
|
||||
}
|
||||
|
||||
fun baz<V : U, U>(<!UNUSED_PARAMETER!>v<!>: V, u: MutableSet<U>) = u
|
||||
|
||||
fun test(a: Any, s: MutableSet<String>) {
|
||||
<!TYPE_INFERENCE_UPPER_BOUND_VIOLATED!>baz<!>(a, s)
|
||||
}
|
||||
@@ -1993,7 +1993,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/inference")
|
||||
@InnerTestClasses({Inference.Regressions.class, Inference.ReportingImprovements.class, Inference.Varargs.class})
|
||||
@InnerTestClasses({Inference.Regressions.class, Inference.ReportingImprovements.class, Inference.UpperBounds.class, Inference.Varargs.class})
|
||||
public static class Inference extends AbstractDiagnosticsTestWithEagerResolve {
|
||||
public void testAllFilesPresentInInference() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/inference"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
@@ -2365,6 +2365,24 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/inference/upperBounds")
|
||||
public static class UpperBounds extends AbstractDiagnosticsTestWithEagerResolve {
|
||||
public void testAllFilesPresentInUpperBounds() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/inference/upperBounds"), "kt", true);
|
||||
}
|
||||
|
||||
@TestMetadata("kt2856.kt")
|
||||
public void testKt2856() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/inference/upperBounds/kt2856.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("useBoundsToInferTypeParamsSimple.kt")
|
||||
public void testUseBoundsToInferTypeParamsSimple() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/inference/upperBounds/useBoundsToInferTypeParamsSimple.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/inference/varargs")
|
||||
public static class Varargs extends AbstractDiagnosticsTestWithEagerResolve {
|
||||
public void testAllFilesPresentInVarargs() throws Exception {
|
||||
@@ -2383,6 +2401,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
||||
suite.addTestSuite(Inference.class);
|
||||
suite.addTestSuite(Regressions.class);
|
||||
suite.addTestSuite(ReportingImprovements.class);
|
||||
suite.addTestSuite(UpperBounds.class);
|
||||
suite.addTestSuite(Varargs.class);
|
||||
return suite;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user