From c0d6eff97c3c8d117813455ba84ae7bb4a10defc Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Mon, 26 Jun 2017 12:50:02 +0300 Subject: [PATCH] [NI] Select variable with proper non-trivial constraint first --- .../components/InferenceStepResolver.kt | 40 ++++++++++++----- .../newInference/fixationOrder1.kt | 13 ++++++ .../newInference/fixationOrder1.txt | 44 +++++++++++++++++++ .../newInference/fixationOrder2.kt | 3 ++ .../newInference/fixationOrder2.txt | 40 +++++++++++++++++ .../kotlin/ir/IrTextTestCaseGenerated.java | 21 +++++++++ 6 files changed, 149 insertions(+), 12 deletions(-) create mode 100644 compiler/testData/ir/irText/regressions/newInference/fixationOrder1.kt create mode 100644 compiler/testData/ir/irText/regressions/newInference/fixationOrder1.txt create mode 100644 compiler/testData/ir/irText/regressions/newInference/fixationOrder2.kt create mode 100644 compiler/testData/ir/irText/regressions/newInference/fixationOrder2.txt diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/InferenceStepResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/InferenceStepResolver.kt index c4e0546bf2e..85073847f9a 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/InferenceStepResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/InferenceStepResolver.kt @@ -16,8 +16,14 @@ package org.jetbrains.kotlin.resolve.calls.inference.components +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter +import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint +import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind import org.jetbrains.kotlin.resolve.calls.inference.model.NotEnoughInformationForTypeParameter +import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints + +typealias VariableResolutionNode = FixationOrderCalculator.NodeWithDirection class InferenceStepResolver( private val resultTypeResolver: ResultTypeResolver @@ -26,18 +32,28 @@ class InferenceStepResolver( * Resolves one or more of the `variables`. * Returns `true` if type variable resolution should stop. */ - fun resolveVariables(c: KotlinCallCompleter.Context, variables: List): Boolean { - for ((variableWithConstraints, direction) in variables) { - if (c.hasContradiction) return true - val variable = variableWithConstraints.typeVariable - val resultType = resultTypeResolver.findResultType(c.asResultTypeResolverContext(), variableWithConstraints, direction) - if (resultType == null) { - c.addError(NotEnoughInformationForTypeParameter(variable)) - break - } - c.fixVariable(variable, resultType) - return false + fun resolveVariables(c: KotlinCallCompleter.Context, variables: List): Boolean { + if (variables.isEmpty()) return true + if (c.hasContradiction) return true + + val nodeToResolve = variables.firstOrNull { it.variableWithConstraints.hasProperConstraint(c) } ?: + variables.first() + val (variableWithConstraints, direction) = nodeToResolve + val variable = variableWithConstraints.typeVariable + + val resultType = resultTypeResolver.findResultType(c.asResultTypeResolverContext(), variableWithConstraints, direction) + if (resultType == null) { + c.addError(NotEnoughInformationForTypeParameter(variable)) + return true } - return true + c.fixVariable(variable, resultType) + return false } + + private fun VariableWithConstraints.hasProperConstraint(c: KotlinCallCompleter.Context) = + constraints.any { !it.isTrivial() && c.canBeProper(it.type) } + + private fun Constraint.isTrivial() = + kind == ConstraintKind.LOWER && KotlinBuiltIns.isNothing(type) || + kind == ConstraintKind.UPPER && KotlinBuiltIns.isNullableAny(type) } \ No newline at end of file diff --git a/compiler/testData/ir/irText/regressions/newInference/fixationOrder1.kt b/compiler/testData/ir/irText/regressions/newInference/fixationOrder1.kt new file mode 100644 index 00000000000..097f3f8a46c --- /dev/null +++ b/compiler/testData/ir/irText/regressions/newInference/fixationOrder1.kt @@ -0,0 +1,13 @@ +fun foo(): (X) -> Y = TODO() + +interface Inv2 + +fun check(x: T, y: R, f: (T) -> R): Inv2 = TODO() + +fun test() = check("", 1, foo()) + +fun box(): String { + val x: Inv2 = test() + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/regressions/newInference/fixationOrder1.txt b/compiler/testData/ir/irText/regressions/newInference/fixationOrder1.txt new file mode 100644 index 00000000000..86277364812 --- /dev/null +++ b/compiler/testData/ir/irText/regressions/newInference/fixationOrder1.txt @@ -0,0 +1,44 @@ +FILE /fixationOrder1.kt + FUN public fun foo(): (X) -> Y + TYPE_PARAMETER + TYPE_PARAMETER + BLOCK_BODY + RETURN type=kotlin.Nothing from='foo(): (X) -> Y' + CALL 'TODO(): Nothing' type=kotlin.Nothing origin=null + CLASS INTERFACE Inv2 + $this: VALUE_PARAMETER this@Inv2: Inv2 + TYPE_PARAMETER + TYPE_PARAMETER + FUN FAKE_OVERRIDE public open override fun equals(other: kotlin.Any?): kotlin.Boolean + $this: VALUE_PARAMETER this@Any: Any + VALUE_PARAMETER value-parameter other: kotlin.Any? + FUN FAKE_OVERRIDE public open override fun hashCode(): kotlin.Int + $this: VALUE_PARAMETER this@Any: Any + FUN FAKE_OVERRIDE public open override fun toString(): kotlin.String + $this: VALUE_PARAMETER this@Any: Any + FUN public fun check(x: T, y: R, f: (T) -> R): Inv2 + TYPE_PARAMETER + TYPE_PARAMETER + VALUE_PARAMETER value-parameter x: T + VALUE_PARAMETER value-parameter y: R + VALUE_PARAMETER value-parameter f: (T) -> R + BLOCK_BODY + RETURN type=kotlin.Nothing from='check(T, R, (T) -> R): Inv2' + CALL 'TODO(): Nothing' type=kotlin.Nothing origin=null + FUN public fun test(): Inv2 + BLOCK_BODY + RETURN type=kotlin.Nothing from='test(): Inv2' + CALL 'check(String, Int, (String) -> Int): Inv2' type=Inv2 origin=null + : String + : Int + x: CONST String type=kotlin.String value='' + y: CONST Int type=kotlin.Int value='1' + f: CALL 'foo(): (String) -> Int' type=(kotlin.String) -> kotlin.Int origin=null + : String + : Int + FUN public fun box(): kotlin.String + BLOCK_BODY + VAR val x: Inv2 + CALL 'test(): Inv2' type=Inv2 origin=null + RETURN type=kotlin.Nothing from='box(): String' + CONST String type=kotlin.String value='OK' diff --git a/compiler/testData/ir/irText/regressions/newInference/fixationOrder2.kt b/compiler/testData/ir/irText/regressions/newInference/fixationOrder2.kt new file mode 100644 index 00000000000..cce576bdfbd --- /dev/null +++ b/compiler/testData/ir/irText/regressions/newInference/fixationOrder2.kt @@ -0,0 +1,3 @@ +fun foo(f: (Y) -> Z, g: (X) -> Y, x: X): Z = f(g(x)) + +fun test() = foo({ it + 1 }, { it.length }, "") \ No newline at end of file diff --git a/compiler/testData/ir/irText/regressions/newInference/fixationOrder2.txt b/compiler/testData/ir/irText/regressions/newInference/fixationOrder2.txt new file mode 100644 index 00000000000..4dbef142dd4 --- /dev/null +++ b/compiler/testData/ir/irText/regressions/newInference/fixationOrder2.txt @@ -0,0 +1,40 @@ +FILE /fixationOrder2.kt + FUN public fun foo(f: (Y) -> Z, g: (X) -> Y, x: X): Z + TYPE_PARAMETER + TYPE_PARAMETER + TYPE_PARAMETER + VALUE_PARAMETER value-parameter f: (Y) -> Z + VALUE_PARAMETER value-parameter g: (X) -> Y + VALUE_PARAMETER value-parameter x: X + BLOCK_BODY + RETURN type=kotlin.Nothing from='foo((Y) -> Z, (X) -> Y, X): Z' + CALL 'invoke(Y): Z' type=Z origin=INVOKE + $this: GET_VAR 'value-parameter f: (Y) -> Z' type=(Y) -> Z origin=VARIABLE_AS_FUNCTION + p1: CALL 'invoke(X): Y' type=Y origin=INVOKE + $this: GET_VAR 'value-parameter g: (X) -> Y' type=(X) -> Y origin=VARIABLE_AS_FUNCTION + p1: GET_VAR 'value-parameter x: X' type=X origin=null + FUN public fun test(): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='test(): Int' + CALL 'foo((Int) -> Int, (String) -> Int, String): Int' type=kotlin.Int origin=null + : String + : Int + : Int + f: BLOCK type=(kotlin.Int) -> kotlin.Int origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA local final fun (it: kotlin.Int): kotlin.Int + VALUE_PARAMETER value-parameter it: kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='(Int): Int' + CALL 'plus(Int): Int' type=kotlin.Int origin=PLUS + $this: GET_VAR 'value-parameter it: Int' type=kotlin.Int origin=null + other: CONST Int type=kotlin.Int value='1' + FUNCTION_REFERENCE '(Int): Int' type=(kotlin.Int) -> kotlin.Int origin=LAMBDA + g: BLOCK type=(kotlin.String) -> kotlin.Int origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA local final fun (it: kotlin.String): kotlin.Int + VALUE_PARAMETER value-parameter it: kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(String): Int' + CALL '(): Int' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR 'value-parameter it: String' type=kotlin.String origin=null + FUNCTION_REFERENCE '(String): Int' type=(kotlin.String) -> kotlin.Int origin=LAMBDA + x: CONST String type=kotlin.String value='' diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index b96b05ececb..109a6c1b981 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -1090,6 +1090,27 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/regressions/typeAliasCtorForGenericClass.kt"); doTest(fileName); } + + @TestMetadata("compiler/testData/ir/irText/regressions/newInference") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class NewInference extends AbstractIrTextTestCase { + public void testAllFilesPresentInNewInference() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/ir/irText/regressions/newInference"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("fixationOrder1.kt") + public void testFixationOrder1() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/regressions/newInference/fixationOrder1.kt"); + doTest(fileName); + } + + @TestMetadata("fixationOrder2.kt") + public void testFixationOrder2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/regressions/newInference/fixationOrder2.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/ir/irText/singletons")