Add expected type constraints in a builder inference call
This commit is contained in:
+16
@@ -12686,6 +12686,22 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
|||||||
runTest("compiler/testData/diagnostics/tests/inference/builderInference/specialCallsWithLambdas.kt");
|
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
|
@Nested
|
||||||
@TestMetadata("compiler/testData/diagnostics/tests/inference/builderInference/stubTypes")
|
@TestMetadata("compiler/testData/diagnostics/tests/inference/builderInference/stubTypes")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+16
@@ -12686,6 +12686,22 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
|||||||
runTest("compiler/testData/diagnostics/tests/inference/builderInference/specialCallsWithLambdas.kt");
|
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
|
@Nested
|
||||||
@TestMetadata("compiler/testData/diagnostics/tests/inference/builderInference/stubTypes")
|
@TestMetadata("compiler/testData/diagnostics/tests/inference/builderInference/stubTypes")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+8
@@ -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.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.reportTrailingLambdaErrorOr
|
import org.jetbrains.kotlin.resolve.calls.callUtil.reportTrailingLambdaErrorOr
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
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.inference.model.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
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 {
|
(position as? ExplicitTypeParameterConstraintPositionImpl)?.let {
|
||||||
val typeArgumentReference = (it.typeArgument as SimpleTypeArgumentImpl).typeReference
|
val typeArgumentReference = (it.typeArgument as SimpleTypeArgumentImpl).typeReference
|
||||||
val diagnosticFactory = if (error.isWarning) UPPER_BOUND_VIOLATED_WARNING else UPPER_BOUND_VIOLATED
|
val diagnosticFactory = if (error.isWarning) UPPER_BOUND_VIOLATED_WARNING else UPPER_BOUND_VIOLATED
|
||||||
|
|||||||
+19
@@ -324,6 +324,23 @@ class BuilderInferenceSession(
|
|||||||
return introducedConstraint
|
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(
|
private fun substituteNotFixedVariables(
|
||||||
lowerType: KotlinType,
|
lowerType: KotlinType,
|
||||||
upperType: KotlinType,
|
upperType: KotlinType,
|
||||||
@@ -530,3 +547,5 @@ class ComposedSubstitutor(val left: NewTypeSubstitutor, val right: NewTypeSubsti
|
|||||||
|
|
||||||
override val isEmpty: Boolean get() = left.isEmpty && right.isEmpty
|
override val isEmpty: Boolean get() = left.isEmpty && right.isEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class BuilderInferenceExpectedTypeConstraintPosition(callElement: KtExpression) : ExpectedTypeConstraintPosition<KtExpression>(callElement)
|
||||||
|
|||||||
@@ -35,15 +35,14 @@ import org.jetbrains.kotlin.resolve.BindingTrace;
|
|||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker;
|
import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker;
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
|
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.calls.smartcasts.*;
|
||||||
import org.jetbrains.kotlin.resolve.constants.*;
|
import org.jetbrains.kotlin.resolve.constants.*;
|
||||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
|
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
import org.jetbrains.kotlin.types.*;
|
||||||
import org.jetbrains.kotlin.types.KotlinTypeKt;
|
|
||||||
import org.jetbrains.kotlin.types.TypeConstructor;
|
|
||||||
import org.jetbrains.kotlin.types.TypeUtils;
|
|
||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||||
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
|
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions;
|
import org.jetbrains.kotlin.util.OperatorNameConventions;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -287,6 +286,11 @@ public class DataFlowAnalyzer {
|
|||||||
@NotNull Ref<Boolean> hasError,
|
@NotNull Ref<Boolean> hasError,
|
||||||
boolean reportErrorForTypeMismatch
|
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() ||
|
if (noExpectedType(c.expectedType) || !c.expectedType.getConstructor().isDenotable() ||
|
||||||
kotlinTypeChecker.isSubtypeOf(expressionType, c.expectedType)) {
|
kotlinTypeChecker.isSubtypeOf(expressionType, c.expectedType)) {
|
||||||
return expressionType;
|
return expressionType;
|
||||||
|
|||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
interface A {
|
||||||
|
fun foo(): MutableList<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
fun main() {
|
||||||
|
buildList {
|
||||||
|
add(3)
|
||||||
|
object : A {
|
||||||
|
override fun foo(): MutableList<String> = this@buildList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buildList {
|
||||||
|
add(3)
|
||||||
|
val x: String = get(0)
|
||||||
|
}
|
||||||
|
buildList {
|
||||||
|
add("3")
|
||||||
|
val x: MutableList<Int> = this@buildList
|
||||||
|
}
|
||||||
|
buildList {
|
||||||
|
val y: CharSequence = ""
|
||||||
|
add(y)
|
||||||
|
val x: MutableList<String> = this@buildList
|
||||||
|
}
|
||||||
|
buildList {
|
||||||
|
add("")
|
||||||
|
val x: MutableList<CharSequence> = this@buildList
|
||||||
|
}
|
||||||
|
buildList {
|
||||||
|
add("")
|
||||||
|
val x: StringBuilder = get(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
interface A {
|
||||||
|
fun foo(): MutableList<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
fun main() {
|
||||||
|
buildList {
|
||||||
|
add(<!CONSTANT_EXPECTED_TYPE_MISMATCH, CONSTANT_EXPECTED_TYPE_MISMATCH!>3<!>)
|
||||||
|
object : A {
|
||||||
|
override fun foo(): MutableList<String> = this@buildList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buildList {
|
||||||
|
add(<!CONSTANT_EXPECTED_TYPE_MISMATCH, CONSTANT_EXPECTED_TYPE_MISMATCH!>3<!>)
|
||||||
|
val x: String = get(0)
|
||||||
|
}
|
||||||
|
buildList {
|
||||||
|
add(<!TYPE_MISMATCH, TYPE_MISMATCH!>"3"<!>)
|
||||||
|
val x: MutableList<Int> = this@buildList
|
||||||
|
}
|
||||||
|
buildList {
|
||||||
|
val y: CharSequence = ""
|
||||||
|
add(<!TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH!>y<!>)
|
||||||
|
val x: MutableList<String> = this@buildList
|
||||||
|
}
|
||||||
|
buildList {
|
||||||
|
add("")
|
||||||
|
val x: MutableList<CharSequence> = this@buildList
|
||||||
|
}
|
||||||
|
buildList {
|
||||||
|
add(<!TYPE_MISMATCH, TYPE_MISMATCH!>""<!>)
|
||||||
|
val x: StringBuilder = get(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -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<kotlin.String>
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
Generated
+16
@@ -12692,6 +12692,22 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/inference/builderInference/specialCallsWithLambdas.kt");
|
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
|
@Nested
|
||||||
@TestMetadata("compiler/testData/diagnostics/tests/inference/builderInference/stubTypes")
|
@TestMetadata("compiler/testData/diagnostics/tests/inference/builderInference/stubTypes")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
Reference in New Issue
Block a user