diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java index 79676debc98..0810318e0ea 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java @@ -36426,6 +36426,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia runTest("compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignment_noReport.kt"); } + @Test + @TestMetadata("upperBoundViolation.kt") + public void testUpperBoundViolation() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/builderInference/upperBoundViolation.kt"); + } + @Test @TestMetadata("useInferenceInformationFromExtension.kt") public void testUseInferenceInformationFromExtension() throws Exception { diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java index c407502148d..14c84f20a6c 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java @@ -36426,6 +36426,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated runTest("compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignment_noReport.kt"); } + @Test + @TestMetadata("upperBoundViolation.kt") + public void testUpperBoundViolation() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/builderInference/upperBoundViolation.kt"); + } + @Test @TestMetadata("useInferenceInformationFromExtension.kt") public void testUseInferenceInformationFromExtension() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java index 3bb8401886f..5b205cca8af 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java @@ -36426,6 +36426,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir runTest("compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignment_noReport.kt"); } + @Test + @TestMetadata("upperBoundViolation.kt") + public void testUpperBoundViolation() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/builderInference/upperBoundViolation.kt"); + } + @Test @TestMetadata("useInferenceInformationFromExtension.kt") public void testUseInferenceInformationFromExtension() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java index f1946c5d459..919ed7c3999 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java @@ -36522,6 +36522,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia runTest("compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignment_noReport.kt"); } + @Test + @TestMetadata("upperBoundViolation.kt") + public void testUpperBoundViolation() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/builderInference/upperBoundViolation.kt"); + } + @Test @TestMetadata("useInferenceInformationFromExtension.kt") public void testUseInferenceInformationFromExtension() throws Exception { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 606dd42b517..b220ed76324 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -884,6 +884,7 @@ public interface Errors { DiagnosticFactory4 STUB_TYPE_IN_RECEIVER_CAUSES_AMBIGUITY = DiagnosticFactory4.create(ERROR); DiagnosticFactory2 BUILDER_INFERENCE_MULTI_LAMBDA_RESTRICTION = DiagnosticFactory2.create(ERROR); DiagnosticFactory2 BUILDER_INFERENCE_STUB_RECEIVER = DiagnosticFactory2.create(ERROR); + DiagnosticFactory4 UPPER_BOUND_VIOLATION_IN_CONSTRAINT = DiagnosticFactory4.create(ERROR); DiagnosticFactory1>> NONE_APPLICABLE = DiagnosticFactory1.create(ERROR); DiagnosticFactory1>> CANNOT_COMPLETE_RESOLVE = DiagnosticFactory1.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 47c87785a84..af52fae260c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -1006,6 +1006,7 @@ public class DefaultErrorMessages { MAP.put(STUB_TYPE_IN_RECEIVER_CAUSES_AMBIGUITY, "The type of a receiver hasn''t been inferred yet. To disambiguate this call, explicitly cast it to `{0}` if you want the builder''s type parameter(s) `{1}` to be inferred to `{2}`.", RENDER_TYPE, STRING, STRING, null); MAP.put(BUILDER_INFERENCE_MULTI_LAMBDA_RESTRICTION, "Unstable inference behaviour with multiple lambdas. Please either specify the type argument for generic parameter `{0}` of `{1}` explicitly", TO_STRING, TO_STRING); MAP.put(BUILDER_INFERENCE_STUB_RECEIVER, "The type of a receiver hasn''t been inferred yet. Please specify type argument for generic parameter `{0}` of `{1}` explicitly", TO_STRING, TO_STRING); + MAP.put(UPPER_BOUND_VIOLATION_IN_CONSTRAINT, "Upper bound violation for generic parameter `{0}` of `{1}`: {3} is not a subtype of {2}", TO_STRING, TO_STRING, RENDER_TYPE, RENDER_TYPE); MAP.put(NONE_APPLICABLE, "None of the following functions can be called with the arguments supplied: {0}", AMBIGUOUS_CALLS); MAP.put(CANNOT_COMPLETE_RESOLVE, "Cannot choose among the following candidates without completing type inference: {0}", AMBIGUOUS_CALLS); MAP.put(UNRESOLVED_REFERENCE_WRONG_RECEIVER, "Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: {0}", AMBIGUOUS_CALLS); 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 420016dbe1a..bb8d109e5e7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt @@ -513,7 +513,20 @@ class DiagnosticReporterByTrackingStrategy( // some error reported later? } is CallableReferenceConstraintPosition<*> -> TODO() - is DeclaredUpperBoundConstraintPosition<*> -> TODO() + is DeclaredUpperBoundConstraintPosition<*> -> { + val originalCall = (position as DeclaredUpperBoundConstraintPositionImpl).kotlinCall + val typeParameterDescriptor = position.typeParameter + val ownerDescriptor = typeParameterDescriptor.containingDeclaration + trace.reportDiagnosticOnce( + UPPER_BOUND_VIOLATION_IN_CONSTRAINT.on( + (originalCall as PSIKotlinCall).psiCall.callElement, + typeParameterDescriptor.name, + ownerDescriptor.name, + error.upperKotlinType, + error.lowerKotlinType + ) + ) + } is DelegatedPropertyConstraintPosition<*> -> { // DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE, reported later } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceArgumentResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceArgumentResolver.kt index 891a7e912cd..fd13bdb66f4 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceArgumentResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceArgumentResolver.kt @@ -39,6 +39,7 @@ class CallableReferenceArgumentResolver(val callableReferenceOverloadConflictRes if (chosenCandidate != null) { val toFreshSubstitutor = CreateFreshVariablesSubstitutor.createToFreshVariableSubstitutorAndAddInitialConstraints( chosenCandidate.candidate, + resolvedAtom.atom.call, csBuilder ) chosenCandidate.addConstraints(csBuilder, toFreshSubstitutor, callableReference = argument) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt index 2a5a399e91c..f9511aaa3d0 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt @@ -124,7 +124,7 @@ internal object CreateFreshVariablesSubstitutor : ResolutionPart() { if (candidateDescriptor.typeParameters.isEmpty()) FreshVariableNewTypeSubstitutor.Empty else - createToFreshVariableSubstitutorAndAddInitialConstraints(candidateDescriptor, csBuilder) + createToFreshVariableSubstitutorAndAddInitialConstraints(candidateDescriptor, resolvedCall.atom, csBuilder) val knownTypeParametersSubstitutor = knownTypeParametersResultingSubstitutor?.let { createKnownParametersFromFreshVariablesSubstitutor(toFreshVariables, it) @@ -220,6 +220,7 @@ internal object CreateFreshVariablesSubstitutor : ResolutionPart() { fun createToFreshVariableSubstitutorAndAddInitialConstraints( candidateDescriptor: CallableDescriptor, + kotlinCall: KotlinCall, csBuilder: ConstraintSystemOperation ): FreshVariableNewTypeSubstitutor { val typeParameters = candidateDescriptor.typeParameters @@ -242,7 +243,7 @@ internal object CreateFreshVariablesSubstitutor : ResolutionPart() { for (index in typeParameters.indices) { val typeParameter = typeParameters[index] val freshVariable = freshTypeVariables[index] - val position = DeclaredUpperBoundConstraintPositionImpl(typeParameter) + val position = DeclaredUpperBoundConstraintPositionImpl(typeParameter, kotlinCall) for (upperBound in typeParameter.upperBounds) { freshVariable.addSubtypeConstraint(upperBound, position) @@ -263,7 +264,7 @@ internal object CreateFreshVariablesSubstitutor : ResolutionPart() { // there can be null in case we already captured type parameter in outer class (in case of inner classes) // see test innerClassTypeAliasConstructor.kt val originalTypeParameter = originalTypeParameters.getOrNull(originalIndex) ?: continue - val position = DeclaredUpperBoundConstraintPositionImpl(originalTypeParameter) + val position = DeclaredUpperBoundConstraintPositionImpl(originalTypeParameter, kotlinCall) for (upperBound in originalTypeParameter.upperBounds) { freshVariable.addSubtypeConstraint(upperBound, position) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintPositionAndErrorsImpl.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintPositionAndErrorsImpl.kt index 649f53576e3..9edb4b0478f 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintPositionAndErrorsImpl.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintPositionAndErrorsImpl.kt @@ -28,7 +28,8 @@ class BuilderInferenceSubstitutionConstraintPositionImpl( class ExpectedTypeConstraintPositionImpl(topLevelCall: KotlinCall) : ExpectedTypeConstraintPosition(topLevelCall) class DeclaredUpperBoundConstraintPositionImpl( - typeParameter: TypeParameterDescriptor + typeParameter: TypeParameterDescriptor, + val kotlinCall: KotlinCall ) : DeclaredUpperBoundConstraintPosition(typeParameter) { override fun toString() = "DeclaredUpperBound ${typeParameter.name} from ${typeParameter.containingDeclaration}" } diff --git a/compiler/testData/diagnostics/testsWithStdLib/builderInference/upperBoundViolation.diag.txt b/compiler/testData/diagnostics/testsWithStdLib/builderInference/upperBoundViolation.diag.txt new file mode 100644 index 00000000000..377e0ac3601 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/builderInference/upperBoundViolation.diag.txt @@ -0,0 +1,4 @@ +/upperBoundViolation.kt:9:9: error: upper bound violation for generic parameter `T` of `printGenericNumber`: String is not a subtype of Number + printGenericNumber(this[0]) + ^ + diff --git a/compiler/testData/diagnostics/testsWithStdLib/builderInference/upperBoundViolation.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/builderInference/upperBoundViolation.fir.kt new file mode 100644 index 00000000000..d2aa03e2109 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/builderInference/upperBoundViolation.fir.kt @@ -0,0 +1,11 @@ +// !RENDER_DIAGNOSTICS_FULL_TEXT +// ISSUE: KT-55055 +// FIR_DUMP +fun printGenericNumber(t: T) = println("Number is $t") + +fun main() { + buildList { // inferred into MutableList + add("Boom") + printGenericNumber(this[0]) + } +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/builderInference/upperBoundViolation.fir.txt b/compiler/testData/diagnostics/testsWithStdLib/builderInference/upperBoundViolation.fir.txt new file mode 100644 index 00000000000..a1bd80e056d --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/builderInference/upperBoundViolation.fir.txt @@ -0,0 +1,11 @@ +FILE: upperBoundViolation.fir.kt + public final fun printGenericNumber(t: R|T|): R|kotlin/Unit| { + ^printGenericNumber R|kotlin/io/println|((String(Number is ), R|/t|)) + } + public final fun main(): R|kotlin/Unit| { + R|kotlin/collections/buildList|( = buildList@fun R|kotlin/collections/MutableList|.(): R|kotlin/Unit| { + this@R|special/anonymous|.R|SubstitutionOverride|(String(Boom)) + R|/printGenericNumber|(this@R|special/anonymous|.R|SubstitutionOverride|(Int(0))) + } + ) + } diff --git a/compiler/testData/diagnostics/testsWithStdLib/builderInference/upperBoundViolation.kt b/compiler/testData/diagnostics/testsWithStdLib/builderInference/upperBoundViolation.kt new file mode 100644 index 00000000000..32817f8e72b --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/builderInference/upperBoundViolation.kt @@ -0,0 +1,11 @@ +// !RENDER_DIAGNOSTICS_FULL_TEXT +// ISSUE: KT-55055 +// FIR_DUMP +fun printGenericNumber(t: T) = println("Number is $t") + +fun main() { + buildList { // inferred into MutableList + add("Boom") + printGenericNumber(this[0]) + } +} 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 cb0445c422c..e83ad9480ac 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 @@ -37258,6 +37258,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignment_noReport.kt"); } + @Test + @TestMetadata("upperBoundViolation.kt") + public void testUpperBoundViolation() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/builderInference/upperBoundViolation.kt"); + } + @Test @TestMetadata("useInferenceInformationFromExtension.kt") public void testUseInferenceInformationFromExtension() throws Exception {