From 90066d7e50b582cb86912cd9eb12f4f66fe76232 Mon Sep 17 00:00:00 2001 From: Victor Petukhov Date: Thu, 29 Apr 2021 11:26:59 +0300 Subject: [PATCH] Add expected type constraints in a builder inference call --- ...irOldFrontendDiagnosticsTestGenerated.java | 16 +++++++++ ...DiagnosticsWithLightTreeTestGenerated.java | 16 +++++++++ .../DiagnosticReporterByTrackingStrategy.kt | 8 +++++ .../inference/BuilderInferenceSession.kt | 19 ++++++++++ .../types/expressions/DataFlowAnalyzer.java | 12 ++++--- .../bySpecifiedReturnType.fir.kt | 36 +++++++++++++++++++ .../bySpecifiedReturnType.kt | 36 +++++++++++++++++++ .../bySpecifiedReturnType.txt | 10 ++++++ .../test/runners/DiagnosticTestGenerated.java | 16 +++++++++ 9 files changed, 165 insertions(+), 4 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints/bySpecifiedReturnType.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints/bySpecifiedReturnType.kt create mode 100644 compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints/bySpecifiedReturnType.txt diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index 7421df8dce5..070867e6333 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -12686,6 +12686,22 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/inference/builderInference/specialCallsWithLambdas.kt"); } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints") + @TestDataPath("$PROJECT_ROOT") + public class AddingConstraints { + @Test + public void testAllFilesPresentInAddingConstraints() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @Test + @TestMetadata("bySpecifiedReturnType.kt") + public void testBySpecifiedReturnType() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints/bySpecifiedReturnType.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/inference/builderInference/stubTypes") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index bccf25fecea..70455267193 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -12686,6 +12686,22 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/inference/builderInference/specialCallsWithLambdas.kt"); } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints") + @TestDataPath("$PROJECT_ROOT") + public class AddingConstraints { + @Test + public void testAllFilesPresentInAddingConstraints() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @Test + @TestMetadata("bySpecifiedReturnType.kt") + public void testBySpecifiedReturnType() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints/bySpecifiedReturnType.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/inference/builderInference/stubTypes") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt index ec42a40c032..e15a2c071f6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.reportTrailingLambdaErrorOr import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext +import org.jetbrains.kotlin.resolve.calls.inference.BuilderInferenceExpectedTypeConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.* import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory @@ -396,6 +397,13 @@ class DiagnosticReporterByTrackingStrategy( } } + (position as? BuilderInferenceExpectedTypeConstraintPosition)?.let { + val inferredType = + if (!error.lowerKotlinType.isNullableNothing()) error.lowerKotlinType + else error.upperKotlinType.makeNullable() + trace.report(TYPE_MISMATCH.on(it.topLevelCall, error.upperKotlinType, inferredType)) + } + (position as? ExplicitTypeParameterConstraintPositionImpl)?.let { val typeArgumentReference = (it.typeArgument as SimpleTypeArgumentImpl).typeReference val diagnosticFactory = if (error.isWarning) UPPER_BOUND_VIOLATED_WARNING else UPPER_BOUND_VIOLATED diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/BuilderInferenceSession.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/BuilderInferenceSession.kt index 8d72b9b6e19..d80f63b32f8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/BuilderInferenceSession.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/BuilderInferenceSession.kt @@ -324,6 +324,23 @@ class BuilderInferenceSession( return introducedConstraint } + fun addExpectedTypeConstraint( + callExpression: KtExpression, + a: KotlinType, + b: KotlinType + ) { + val nonFixedToVariablesSubstitutor: NewTypeSubstitutor = createNonFixedTypeToVariableSubstitutor() + val (lower, upper) = substituteNotFixedVariables(a, b, nonFixedToVariablesSubstitutor) + val position = BuilderInferenceExpectedTypeConstraintPosition(callExpression) + val currentSubstitutor = commonSystem.buildCurrentSubstitutor() + + commonSystem.addSubtypeConstraint( + currentSubstitutor.safeSubstitute(commonSystem.typeSystemContext, lower), + currentSubstitutor.safeSubstitute(commonSystem.typeSystemContext, upper), + position + ) + } + private fun substituteNotFixedVariables( lowerType: KotlinType, upperType: KotlinType, @@ -530,3 +547,5 @@ class ComposedSubstitutor(val left: NewTypeSubstitutor, val right: NewTypeSubsti override val isEmpty: Boolean get() = left.isEmpty && right.isEmpty } + +class BuilderInferenceExpectedTypeConstraintPosition(callElement: KtExpression) : ExpectedTypeConstraintPosition(callElement) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java index 8a740859c43..526f232c916 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java @@ -35,15 +35,14 @@ import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker; import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext; +import org.jetbrains.kotlin.resolve.calls.inference.BuilderInferenceSession; import org.jetbrains.kotlin.resolve.calls.smartcasts.*; import org.jetbrains.kotlin.resolve.constants.*; import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator; -import org.jetbrains.kotlin.types.KotlinType; -import org.jetbrains.kotlin.types.KotlinTypeKt; -import org.jetbrains.kotlin.types.TypeConstructor; -import org.jetbrains.kotlin.types.TypeUtils; +import org.jetbrains.kotlin.types.*; import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt; +import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt; import org.jetbrains.kotlin.util.OperatorNameConventions; import java.util.Collection; @@ -287,6 +286,11 @@ public class DataFlowAnalyzer { @NotNull Ref hasError, boolean reportErrorForTypeMismatch ) { + if (!noExpectedType(c.expectedType) && TypeUtilsKt.contains(expressionType, (type) -> type instanceof StubType)) { + if (c.inferenceSession instanceof BuilderInferenceSession) { + ((BuilderInferenceSession) c.inferenceSession).addExpectedTypeConstraint(expression, expressionType, c.expectedType); + } + } if (noExpectedType(c.expectedType) || !c.expectedType.getConstructor().isDenotable() || kotlinTypeChecker.isSubtypeOf(expressionType, c.expectedType)) { return expressionType; diff --git a/compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints/bySpecifiedReturnType.fir.kt b/compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints/bySpecifiedReturnType.fir.kt new file mode 100644 index 00000000000..b805ca8b5cd --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints/bySpecifiedReturnType.fir.kt @@ -0,0 +1,36 @@ +// WITH_RUNTIME + +interface A { + fun foo(): MutableList +} + +@ExperimentalStdlibApi +fun main() { + buildList { + add(3) + object : A { + override fun foo(): MutableList = this@buildList + } + } + buildList { + add(3) + val x: String = get(0) + } + buildList { + add("3") + val x: MutableList = this@buildList + } + buildList { + val y: CharSequence = "" + add(y) + val x: MutableList = this@buildList + } + buildList { + add("") + val x: MutableList = this@buildList + } + buildList { + add("") + val x: StringBuilder = get(0) + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints/bySpecifiedReturnType.kt b/compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints/bySpecifiedReturnType.kt new file mode 100644 index 00000000000..9dec54e4b28 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints/bySpecifiedReturnType.kt @@ -0,0 +1,36 @@ +// WITH_RUNTIME + +interface A { + fun foo(): MutableList +} + +@ExperimentalStdlibApi +fun main() { + buildList { + add(3) + object : A { + override fun foo(): MutableList = this@buildList + } + } + buildList { + add(3) + val x: String = get(0) + } + buildList { + add("3") + val x: MutableList = this@buildList + } + buildList { + val y: CharSequence = "" + add(y) + val x: MutableList = this@buildList + } + buildList { + add("") + val x: MutableList = this@buildList + } + buildList { + add("") + val x: StringBuilder = get(0) + } +} diff --git a/compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints/bySpecifiedReturnType.txt b/compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints/bySpecifiedReturnType.txt new file mode 100644 index 00000000000..be25776a15c --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints/bySpecifiedReturnType.txt @@ -0,0 +1,10 @@ +package + +@kotlin.ExperimentalStdlibApi public fun main(): kotlin.Unit + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.collections.MutableList + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index 53d51b53061..3d5a718aeab 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -12692,6 +12692,22 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/inference/builderInference/specialCallsWithLambdas.kt"); } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints") + @TestDataPath("$PROJECT_ROOT") + public class AddingConstraints { + @Test + public void testAllFilesPresentInAddingConstraints() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @Test + @TestMetadata("bySpecifiedReturnType.kt") + public void testBySpecifiedReturnType() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/builderInference/addingConstraints/bySpecifiedReturnType.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/inference/builderInference/stubTypes") @TestDataPath("$PROJECT_ROOT")