From dc42b20ae32d6b6e22b95fce46032a675bfabe3f Mon Sep 17 00:00:00 2001 From: Pavel Kirpichenkov Date: Thu, 20 Feb 2020 19:55:13 +0300 Subject: [PATCH] [NI] Use alternative to intersection type in public declarations The new inference uses inferred intersection types normally, unlike the old inference. However, intersection types in public declarations are approximated to supertype, which potentially may give a less presice type, then it would be with the OI. For non-related T1, T2 the NI approximates {T1 & T2} to Any in public declarations, and if the OI was inferring T1 instead of the intersection type, it may lead to less precise declaration type and related errors. The solution is to remember an alternative for an intersection type when present. Before approximation the alternative replaces the intersection type. ^KT-36249 Fixed --- .../kotlin/fir/types/ConeTypeContext.kt | 7 ++ ...irOldFrontendDiagnosticsTestGenerated.java | 83 +++++++++++++++++++ ...endDiagnosticsTestWithStdlibGenerated.java | 5 ++ .../kotlin/resolve/calls/CallResolverUtil.kt | 11 ++- .../calls/smartcasts/SmartCastManager.kt | 2 - .../components/NewTypeSubstitutor.kt | 12 ++- .../components/ResultTypeResolver.kt | 23 ++++- .../model/NewConstraintSystemImpl.kt | 4 +- .../kotlin/types/TypeApproximator.kt | 3 +- .../types/alternativeTypeSubstitution.kt | 29 +++++++ ...ximatedIntersectionMorePreciseThanBound.kt | 20 +++++ ...imatedIntersectionMorePreciseThanBound.txt | 50 +++++++++++ .../publicApproximation/chainedLambdas.fir.kt | 34 ++++++++ .../publicApproximation/chainedLambdas.kt | 34 ++++++++ .../publicApproximation/chainedLambdas.ni.txt | 30 +++++++ .../publicApproximation/chainedLambdas.txt | 30 +++++++ .../declarationTypes.fir.kt | 59 +++++++++++++ .../publicApproximation/declarationTypes.kt | 59 +++++++++++++ .../publicApproximation/declarationTypes.txt | 57 +++++++++++++ ...sectionAfterSmartCastInLambdaReturn.fir.kt | 38 +++++++++ ...ntersectionAfterSmartCastInLambdaReturn.kt | 38 +++++++++ ...sectionAfterSmartCastInLambdaReturn.ni.txt | 50 +++++++++++ ...tersectionAfterSmartCastInLambdaReturn.txt | 50 +++++++++++ .../intersectionAlternative.fir.kt | 17 ++++ .../intersectionAlternative.kt | 17 ++++ .../intersectionAlternative.txt | 43 ++++++++++ .../intersectionLocations.fir.kt | 44 ++++++++++ .../intersectionLocations.kt | 44 ++++++++++ .../intersectionLocations.txt | 71 ++++++++++++++++ .../lambdaReturnArgumentCall.fir.kt | 19 +++++ .../lambdaReturnArgumentCall.kt | 19 +++++ .../lambdaReturnArgumentCall.txt | 29 +++++++ .../lambdaReturnTypeApproximation.fir.kt | 20 +++++ .../lambdaReturnTypeApproximation.kt | 20 +++++ .../lambdaReturnTypeApproximation.txt | 32 +++++++ .../nonTrivialVariance.fir.kt | 54 ++++++++++++ .../publicApproximation/nonTrivialVariance.kt | 54 ++++++++++++ .../nonTrivialVariance.txt | 71 ++++++++++++++++ .../parameterInBound.fir.kt | 25 ++++++ .../publicApproximation/parameterInBound.kt | 25 ++++++ .../publicApproximation/parameterInBound.txt | 58 +++++++++++++ .../publicApproximation/projections.fir.kt | 19 +++++ .../publicApproximation/projections.kt | 19 +++++ .../publicApproximation/projections.txt | 40 +++++++++ ...CastInLambdaReturnAfterIntersection.fir.kt | 22 +++++ ...martCastInLambdaReturnAfterIntersection.kt | 22 +++++ ...CastInLambdaReturnAfterIntersection.ni.txt | 32 +++++++ ...artCastInLambdaReturnAfterIntersection.txt | 32 +++++++ .../twoIntersections.fir.kt | 25 ++++++ .../publicApproximation/twoIntersections.kt | 25 ++++++ .../twoIntersections.ni.txt | 70 ++++++++++++++++ .../publicApproximation/twoIntersections.txt | 70 ++++++++++++++++ .../inference/topLevelIntersection.fir.kt | 17 ++++ .../tests/inference/topLevelIntersection.kt | 17 ++++ .../tests/inference/topLevelIntersection.txt | 38 +++++++++ ...peArgumentsInferenceWithNestedCalls.ni.txt | 2 +- .../testsWithStdLib/inference/kt36249.fir.kt | 18 ++++ .../testsWithStdLib/inference/kt36249.kt | 18 ++++ .../testsWithStdLib/inference/kt36249.txt | 36 ++++++++ .../implicitCastToTypeParameter.txt | 18 ++-- .../checkers/DiagnosticsTestGenerated.java | 83 +++++++++++++++++++ .../DiagnosticsTestWithStdLibGenerated.java | 5 ++ ...ticsTestWithStdLibUsingJavacGenerated.java | 5 ++ .../DiagnosticsUsingJavacTestGenerated.java | 83 +++++++++++++++++++ .../types/IntersectionTypeConstructor.kt | 23 ++++- .../types/checker/ClassicTypeSystemContext.kt | 16 ++++ .../kotlin/types/model/TypeSystemContext.kt | 5 ++ 67 files changed, 2120 insertions(+), 30 deletions(-) create mode 100644 compiler/resolution/src/org/jetbrains/kotlin/types/alternativeTypeSubstitution.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/approximatedIntersectionMorePreciseThanBound.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/approximatedIntersectionMorePreciseThanBound.txt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/chainedLambdas.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/chainedLambdas.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/chainedLambdas.ni.txt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/chainedLambdas.txt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/declarationTypes.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/declarationTypes.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/declarationTypes.txt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAfterSmartCastInLambdaReturn.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAfterSmartCastInLambdaReturn.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAfterSmartCastInLambdaReturn.ni.txt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAfterSmartCastInLambdaReturn.txt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAlternative.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAlternative.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAlternative.txt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionLocations.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionLocations.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionLocations.txt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnArgumentCall.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnArgumentCall.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnArgumentCall.txt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnTypeApproximation.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnTypeApproximation.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnTypeApproximation.txt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/nonTrivialVariance.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/nonTrivialVariance.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/nonTrivialVariance.txt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/parameterInBound.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/parameterInBound.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/parameterInBound.txt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/projections.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/projections.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/projections.txt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/smartCastInLambdaReturnAfterIntersection.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/smartCastInLambdaReturnAfterIntersection.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/smartCastInLambdaReturnAfterIntersection.ni.txt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/smartCastInLambdaReturnAfterIntersection.txt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/twoIntersections.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/twoIntersections.kt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/twoIntersections.ni.txt create mode 100644 compiler/testData/diagnostics/tests/inference/publicApproximation/twoIntersections.txt create mode 100644 compiler/testData/diagnostics/tests/inference/topLevelIntersection.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/topLevelIntersection.kt create mode 100644 compiler/testData/diagnostics/tests/inference/topLevelIntersection.txt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/inference/kt36249.fir.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/inference/kt36249.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/inference/kt36249.txt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt index 81303465cf1..6d289b0911c 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt @@ -557,4 +557,11 @@ class ConeTypeCheckerContext( else ConeTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything, session) + override fun createTypeWithAlternativeForIntersectionResult( + firstCandidate: KotlinTypeMarker, + secondCandidate: KotlinTypeMarker + ): KotlinTypeMarker { + TODO("Not yet implemented") + } + } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index 620beb7814f..c6ca1b3d0ee 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -10226,6 +10226,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/inference/tooEagerSmartcast.kt"); } + @TestMetadata("topLevelIntersection.kt") + public void testTopLevelIntersection() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/topLevelIntersection.kt"); + } + @TestMetadata("tryNumberLowerBoundsBeforeUpperBounds.kt") public void testTryNumberLowerBoundsBeforeUpperBounds() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/tryNumberLowerBoundsBeforeUpperBounds.kt"); @@ -11022,6 +11027,84 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte } } + @TestMetadata("compiler/testData/diagnostics/tests/inference/publicApproximation") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class PublicApproximation extends AbstractFirOldFrontendDiagnosticsTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInPublicApproximation() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/publicApproximation"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @TestMetadata("approximatedIntersectionMorePreciseThanBound.kt") + public void testApproximatedIntersectionMorePreciseThanBound() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/approximatedIntersectionMorePreciseThanBound.kt"); + } + + @TestMetadata("chainedLambdas.kt") + public void testChainedLambdas() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/chainedLambdas.kt"); + } + + @TestMetadata("declarationTypes.kt") + public void testDeclarationTypes() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/declarationTypes.kt"); + } + + @TestMetadata("intersectionAfterSmartCastInLambdaReturn.kt") + public void testIntersectionAfterSmartCastInLambdaReturn() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAfterSmartCastInLambdaReturn.kt"); + } + + @TestMetadata("intersectionAlternative.kt") + public void testIntersectionAlternative() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAlternative.kt"); + } + + @TestMetadata("intersectionLocations.kt") + public void testIntersectionLocations() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionLocations.kt"); + } + + @TestMetadata("lambdaReturnArgumentCall.kt") + public void testLambdaReturnArgumentCall() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnArgumentCall.kt"); + } + + @TestMetadata("lambdaReturnTypeApproximation.kt") + public void testLambdaReturnTypeApproximation() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnTypeApproximation.kt"); + } + + @TestMetadata("nonTrivialVariance.kt") + public void testNonTrivialVariance() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/nonTrivialVariance.kt"); + } + + @TestMetadata("parameterInBound.kt") + public void testParameterInBound() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/parameterInBound.kt"); + } + + @TestMetadata("projections.kt") + public void testProjections() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/projections.kt"); + } + + @TestMetadata("smartCastInLambdaReturnAfterIntersection.kt") + public void testSmartCastInLambdaReturnAfterIntersection() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/smartCastInLambdaReturnAfterIntersection.kt"); + } + + @TestMetadata("twoIntersections.kt") + public void testTwoIntersections() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/twoIntersections.kt"); + } + } + @TestMetadata("compiler/testData/diagnostics/tests/inference/recursiveCalls") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestWithStdlibGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestWithStdlibGenerated.java index 928fda2a2bb..873cae3d933 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestWithStdlibGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestWithStdlibGenerated.java @@ -1901,6 +1901,11 @@ public class FirOldFrontendDiagnosticsTestWithStdlibGenerated extends AbstractFi runTest("compiler/testData/diagnostics/testsWithStdLib/inference/kt35847.kt"); } + @TestMetadata("kt36249.kt") + public void testKt36249() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/kt36249.kt"); + } + @TestMetadata("kt4975.kt") public void testKt4975() throws Exception { runTest("compiler/testData/diagnostics/testsWithStdLib/inference/kt4975.kt"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt index 07c041eeec3..a4f47479855 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt @@ -113,15 +113,14 @@ fun getErasedReceiverType(receiverParameterDescriptor: ReceiverParameterDescript fakeTypeArguments.add(TypeProjectionImpl(typeProjection.projectionKind, DONT_CARE)) } - val receiverTypeConstructor = if (receiverType.constructor is IntersectionTypeConstructor) { - val superTypesWithFakeArguments = receiverType.constructor.supertypes.map { supertype -> + val oldReceiverTypeConstructor = receiverType.constructor + val receiverTypeConstructor = if (oldReceiverTypeConstructor is IntersectionTypeConstructor) { + oldReceiverTypeConstructor.transformComponents { supertype -> val fakeArguments = supertype.arguments.map { TypeProjectionImpl(it.projectionKind, DONT_CARE) } supertype.replace(fakeArguments) - } - - IntersectionTypeConstructor(superTypesWithFakeArguments) + } ?: oldReceiverTypeConstructor } else { - receiverType.constructor + oldReceiverTypeConstructor } return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/SmartCastManager.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/SmartCastManager.kt index 19a706b527c..038b04c637e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/SmartCastManager.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/SmartCastManager.kt @@ -34,8 +34,6 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils -import org.jetbrains.kotlin.types.checker.TypeIntersector -import org.jetbrains.kotlin.types.checker.intersectTypes import org.jetbrains.kotlin.types.checker.intersectWrappedTypes import org.jetbrains.kotlin.types.typeUtil.expandIntersectionTypeIfNecessary import org.jetbrains.kotlin.utils.addIfNotNull diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/NewTypeSubstitutor.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/NewTypeSubstitutor.kt index 8f827a053d8..4bb9ca05567 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/NewTypeSubstitutor.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/NewTypeSubstitutor.kt @@ -106,12 +106,16 @@ interface NewTypeSubstitutor: TypeSubstitutorMarker { } if (typeConstructor is IntersectionTypeConstructor) { - var thereIsChanges = false + fun updateNullability(substituted: UnwrappedType) = + if (type.isMarkedNullable) substituted.makeNullableAsSpecified(true) else substituted + + substituteNotNullTypeWithConstructor(typeConstructor)?.let { return updateNullability(it) } + var thereAreChanges = false val newTypes = typeConstructor.supertypes.map { - substitute(it.unwrap(), keepAnnotation, runCapturedChecks)?.apply { thereIsChanges = true } ?: it.unwrap() + substitute(it.unwrap(), keepAnnotation, runCapturedChecks)?.apply { thereAreChanges = true } ?: it.unwrap() } - if (!thereIsChanges) return null - return intersectTypes(newTypes).let { if (type.isMarkedNullable) it.makeNullableAsSpecified(true) else it } + if (!thereAreChanges) return null + return updateNullability(intersectTypes(newTypes)) } // simple classifier type diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt index d65374540c6..94fc5aacaa8 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt @@ -19,8 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.inference.components import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator import org.jetbrains.kotlin.resolve.calls.inference.components.TypeVariableDirectionCalculator.ResolveDirection import org.jetbrains.kotlin.resolve.calls.inference.model.* -import org.jetbrains.kotlin.types.AbstractTypeApproximator -import org.jetbrains.kotlin.types.TypeApproximatorConfiguration +import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.model.* class ResultTypeResolver( @@ -65,6 +64,10 @@ class ResultTypeResolver( ): KotlinTypeMarker? { if (firstCandidate == null || secondCandidate == null) return firstCandidate ?: secondCandidate + specialResultForIntersectionType(firstCandidate, secondCandidate)?.let { intersectionWithAlternative -> + return intersectionWithAlternative + } + if (isSuitableType(firstCandidate, variableWithConstraints)) return firstCandidate return if (isSuitableType(secondCandidate, variableWithConstraints)) { @@ -74,6 +77,22 @@ class ResultTypeResolver( } } + private fun Context.specialResultForIntersectionType( + firstCandidate: KotlinTypeMarker, + secondCandidate: KotlinTypeMarker, + ): KotlinTypeMarker? { + if (firstCandidate.typeConstructor() is IntersectionTypeConstructor) { + if (!AbstractTypeChecker.isSubtypeOf(this, firstCandidate.toPublicType(), secondCandidate.toPublicType())) { + return createTypeWithAlternativeForIntersectionResult(firstCandidate, secondCandidate) + } + } + + return null + } + + private fun KotlinTypeMarker.toPublicType(): KotlinTypeMarker = + typeApproximator.approximateToSuperType(this, TypeApproximatorConfiguration.PublicDeclaration) ?: this + private fun Context.isSuitableType(resultType: KotlinTypeMarker, variableWithConstraints: VariableWithConstraints): Boolean { val filteredConstraints = variableWithConstraints.constraints.filter { isProperType(it.type) } for (constraint in filteredConstraints) { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt index 9053dc8167a..7f91901e128 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt @@ -13,9 +13,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolve import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic import org.jetbrains.kotlin.resolve.calls.model.OnlyInputTypesDiagnostic import org.jetbrains.kotlin.resolve.calls.model.ResolvedAtom -import org.jetbrains.kotlin.types.AbstractTypeChecker -import org.jetbrains.kotlin.types.IntersectionTypeConstructor -import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker import org.jetbrains.kotlin.types.model.* import org.jetbrains.kotlin.utils.SmartList diff --git a/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt b/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt index 44b048875a6..dc1be049f1e 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt @@ -115,7 +115,8 @@ class TypeApproximator(builtIns: KotlinBuiltIns) : AbstractTypeApproximator(Clas if (!languageVersionSettings.supportsFeature(LanguageFeature.NewInference)) return baseType.unwrap() val configuration = if (local) TypeApproximatorConfiguration.LocalDeclaration else TypeApproximatorConfiguration.PublicDeclaration - return approximateToSuperType(baseType.unwrap(), configuration) ?: baseType.unwrap() + val preparedType = if (local) baseType.unwrap() else substituteAlternativesInPublicType(baseType) + return approximateToSuperType(preparedType, configuration) ?: preparedType } // null means that this input type is the result, i.e. input type not contains not-allowed kind of types diff --git a/compiler/resolution/src/org/jetbrains/kotlin/types/alternativeTypeSubstitution.kt b/compiler/resolution/src/org/jetbrains/kotlin/types/alternativeTypeSubstitution.kt new file mode 100644 index 00000000000..71f93f7f75d --- /dev/null +++ b/compiler/resolution/src/org/jetbrains/kotlin/types/alternativeTypeSubstitution.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.types + +import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor +import org.jetbrains.kotlin.types.typeUtil.contains + +fun substituteAlternativesInPublicType(type: KotlinType): UnwrappedType { + val substitutor = object : NewTypeSubstitutor { + override fun substituteNotNullTypeWithConstructor(constructor: TypeConstructor): UnwrappedType? { + if (constructor is IntersectionTypeConstructor) { + constructor.getAlternativeType()?.let { alternative -> + return safeSubstitute(alternative.unwrap()) + } + } + + return null + } + + override val isEmpty: Boolean by lazy { + !type.contains { it.constructor is IntersectionTypeConstructor } + } + } + + return substitutor.safeSubstitute(type.unwrap()) +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/approximatedIntersectionMorePreciseThanBound.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/approximatedIntersectionMorePreciseThanBound.kt new file mode 100644 index 00000000000..0bec3ef6b20 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/approximatedIntersectionMorePreciseThanBound.kt @@ -0,0 +1,20 @@ +// FIR_IDENTICAL +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !LANGUAGE: +NewInference + +interface Bound { + fun foo() {} +} +interface Bound1 : Bound +interface Bound2 : Bound +object First : Bound1, Bound2 +object Second : Bound1, Bound2 + +class Out(val param: O) + +fun anyBound(vararg elements: S): Out = TODO() +fun topLevel() = anyBound(First, Second) + +fun test() { + topLevel().param.foo() +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/approximatedIntersectionMorePreciseThanBound.txt b/compiler/testData/diagnostics/tests/inference/publicApproximation/approximatedIntersectionMorePreciseThanBound.txt new file mode 100644 index 00000000000..6ce90f2406e --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/approximatedIntersectionMorePreciseThanBound.txt @@ -0,0 +1,50 @@ +package + +public fun anyBound(/*0*/ vararg elements: S /*kotlin.Array*/): Out +public fun test(): kotlin.Unit +public fun topLevel(): Out + +public interface Bound { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Bound1 : Bound { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Bound2 : Bound { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object First : Bound1, Bound2 { + private constructor First() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Out { + public constructor Out(/*0*/ param: O) + public final val param: O + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object Second : Bound1, Bound2 { + private constructor Second() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/chainedLambdas.fir.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/chainedLambdas.fir.kt new file mode 100644 index 00000000000..0059860e2bb --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/chainedLambdas.fir.kt @@ -0,0 +1,34 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !WITH_NEW_INFERENCE +// NI_EXPECTED_FILE + +interface First { + fun first() {} +} +interface Second +interface Third +interface Fourth + +fun chained1(arg: First) = run { + if (arg !is Second) throw Exception() + arg +}.let { third -> + if (third !is Third) throw Exception() + third +} + +fun chained2(arg: First) = run { + if (arg !is Second) throw Exception() + arg +}.let { third -> + if (third !is Third) throw Exception() + third +}.let { fourth -> + if (fourth !is Fourth) throw Exception() + fourth +} + +fun test(arg: First) { + chained1(arg).first() + chained2(arg).first() +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/chainedLambdas.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/chainedLambdas.kt new file mode 100644 index 00000000000..89184ee31a2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/chainedLambdas.kt @@ -0,0 +1,34 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !WITH_NEW_INFERENCE +// NI_EXPECTED_FILE + +interface First { + fun first() {} +} +interface Second +interface Third +interface Fourth + +fun chained1(arg: First) = run { + if (arg !is Second) throw Exception() + arg +}.let { third -> + if (third !is Third) throw Exception() + third +} + +fun chained2(arg: First) = run { + if (arg !is Second) throw Exception() + arg +}.let { third -> + if (third !is Third) throw Exception() + third +}.let { fourth -> + if (fourth !is Fourth) throw Exception() + fourth +} + +fun test(arg: First) { + chained1(arg).first() + chained2(arg).first() +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/chainedLambdas.ni.txt b/compiler/testData/diagnostics/tests/inference/publicApproximation/chainedLambdas.ni.txt new file mode 100644 index 00000000000..3b61b201485 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/chainedLambdas.ni.txt @@ -0,0 +1,30 @@ +package + +public fun chained1(/*0*/ arg: First): kotlin.Any +public fun chained2(/*0*/ arg: First): kotlin.Any +public fun test(/*0*/ arg: First): kotlin.Unit + +public interface First { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun first(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Fourth { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Second { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Third { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/chainedLambdas.txt b/compiler/testData/diagnostics/tests/inference/publicApproximation/chainedLambdas.txt new file mode 100644 index 00000000000..ad47684e487 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/chainedLambdas.txt @@ -0,0 +1,30 @@ +package + +public fun chained1(/*0*/ arg: First): First +public fun chained2(/*0*/ arg: First): First +public fun test(/*0*/ arg: First): kotlin.Unit + +public interface First { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun first(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Fourth { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Second { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Third { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/declarationTypes.fir.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/declarationTypes.fir.kt new file mode 100644 index 00000000000..e177d28b10c --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/declarationTypes.fir.kt @@ -0,0 +1,59 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -UNUSED_EXPRESSION +// !LANGUAGE: +NewInference + +interface Bound1 +interface Bound2 +object First : Bound1, Bound2 +object Second : Bound1, Bound2 + +fun intersect(vararg elements: S): S = TODO() + +fun topLevelFunction() = intersect(First, Second) +val Any.extensionProperty + get() = intersect(First, Second) + +fun Any.extensionFunction() = intersect(First, Second) + +class Cls { + val publicProperty = intersect(First, Second) + private val privateProperty = intersect(First, Second) + + fun publicMemberFunction() = intersect(First, Second) + private fun privateMemberFunction() = intersect(First, Second) + + fun testLocalDeclarations() { + val localVariable = intersect(First, Second) + fun localFunction() = intersect(First, Second) + localVariable + privateProperty + localFunction() + privateMemberFunction() + } +} + +object Obj { + val publicProperty = intersect(First, Second) + private val privateProperty = intersect(First, Second) + + fun publicMemberFunction() = intersect(First, Second) + private fun privateMemberFunction() = intersect(First, Second) + + fun testLocalDeclarations() { + val localVariable = intersect(First, Second) + fun localFunction() = intersect(First, Second) + localVariable + localFunction() + privateProperty + privateMemberFunction() + } +} + +fun test(cls: Cls, obj: Obj) { + topLevelFunction() + Unit.extensionProperty + Unit.extensionFunction() + cls.publicProperty + cls.publicMemberFunction() + obj.publicProperty + obj.publicMemberFunction() +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/declarationTypes.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/declarationTypes.kt new file mode 100644 index 00000000000..219aa252e46 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/declarationTypes.kt @@ -0,0 +1,59 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -UNUSED_EXPRESSION +// !LANGUAGE: +NewInference + +interface Bound1 +interface Bound2 +object First : Bound1, Bound2 +object Second : Bound1, Bound2 + +fun intersect(vararg elements: S): S = TODO() + +fun topLevelFunction() = intersect(First, Second) +val Any.extensionProperty + get() = intersect(First, Second) + +fun Any.extensionFunction() = intersect(First, Second) + +class Cls { + val publicProperty = intersect(First, Second) + private val privateProperty = intersect(First, Second) + + fun publicMemberFunction() = intersect(First, Second) + private fun privateMemberFunction() = intersect(First, Second) + + fun testLocalDeclarations() { + val localVariable = intersect(First, Second) + fun localFunction() = intersect(First, Second) + localVariable + privateProperty + localFunction() + privateMemberFunction() + } +} + +object Obj { + val publicProperty = intersect(First, Second) + private val privateProperty = intersect(First, Second) + + fun publicMemberFunction() = intersect(First, Second) + private fun privateMemberFunction() = intersect(First, Second) + + fun testLocalDeclarations() { + val localVariable = intersect(First, Second) + fun localFunction() = intersect(First, Second) + localVariable + localFunction() + privateProperty + privateMemberFunction() + } +} + +fun test(cls: Cls, obj: Obj) { + topLevelFunction() + Unit.extensionProperty + Unit.extensionFunction() + cls.publicProperty + cls.publicMemberFunction() + obj.publicProperty + obj.publicMemberFunction() +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/declarationTypes.txt b/compiler/testData/diagnostics/tests/inference/publicApproximation/declarationTypes.txt new file mode 100644 index 00000000000..6cf11cb3de4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/declarationTypes.txt @@ -0,0 +1,57 @@ +package + +public val kotlin.Any.extensionProperty: Bound1 +public fun intersect(/*0*/ vararg elements: S /*kotlin.Array*/): S +public fun test(/*0*/ cls: Cls, /*1*/ obj: Obj): kotlin.Unit +public fun topLevelFunction(): Bound1 +public fun kotlin.Any.extensionFunction(): Bound1 + +public interface Bound1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Bound2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Cls { + public constructor Cls() + private final val privateProperty: Bound1 + public final val publicProperty: Bound1 + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + private final fun privateMemberFunction(): Bound1 + public final fun publicMemberFunction(): Bound1 + public final fun testLocalDeclarations(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object First : Bound1, Bound2 { + private constructor First() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object Obj { + private constructor Obj() + private final val privateProperty: Bound1 + public final val publicProperty: Bound1 + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + private final fun privateMemberFunction(): Bound1 + public final fun publicMemberFunction(): Bound1 + public final fun testLocalDeclarations(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object Second : Bound1, Bound2 { + private constructor Second() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAfterSmartCastInLambdaReturn.fir.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAfterSmartCastInLambdaReturn.fir.kt new file mode 100644 index 00000000000..23cdcc38c3f --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAfterSmartCastInLambdaReturn.fir.kt @@ -0,0 +1,38 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !WITH_NEW_INFERENCE +// NI_EXPECTED_FILE + +interface Base { + fun base() {} +} +interface Base2 +interface One : Base, Base2 +interface Two : Base, Base2 + +object O1 : One +object O2 : Two + +fun intersect(vararg elements: S): S = TODO() + +fun intersectAfterSmartCast(arg: Base, arg2: Base) = intersect( + run { + if (arg !is One) throw Exception() + arg + }, + run { + if (arg2 !is Two) throw Exception() + arg2 + } +) + +fun argOrFn(arg: S, fn: () -> S): S = TODO() + +fun intersectArgWithSmartCastFromLambda(arg: One, arg2: Base) = argOrFn(arg) { + if (arg2 !is Two) throw Exception() + arg2 +} + +fun test() { + intersectAfterSmartCast(O1, O2).base() + intersectArgWithSmartCastFromLambda(O1, O2).base() +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAfterSmartCastInLambdaReturn.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAfterSmartCastInLambdaReturn.kt new file mode 100644 index 00000000000..c8c08df2c07 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAfterSmartCastInLambdaReturn.kt @@ -0,0 +1,38 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !WITH_NEW_INFERENCE +// NI_EXPECTED_FILE + +interface Base { + fun base() {} +} +interface Base2 +interface One : Base, Base2 +interface Two : Base, Base2 + +object O1 : One +object O2 : Two + +fun intersect(vararg elements: S): S = TODO() + +fun intersectAfterSmartCast(arg: Base, arg2: Base) = intersect( + run { + if (arg !is One) throw Exception() + arg + }, + run { + if (arg2 !is Two) throw Exception() + arg2 + } +) + +fun argOrFn(arg: S, fn: () -> S): S = TODO() + +fun intersectArgWithSmartCastFromLambda(arg: One, arg2: Base) = argOrFn(arg) { + if (arg2 !is Two) throw Exception() + arg2 +} + +fun test() { + intersectAfterSmartCast(O1, O2).base() + intersectArgWithSmartCastFromLambda(O1, O2).base() +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAfterSmartCastInLambdaReturn.ni.txt b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAfterSmartCastInLambdaReturn.ni.txt new file mode 100644 index 00000000000..a87e0df8457 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAfterSmartCastInLambdaReturn.ni.txt @@ -0,0 +1,50 @@ +package + +public fun argOrFn(/*0*/ arg: S, /*1*/ fn: () -> S): S +public fun intersect(/*0*/ vararg elements: S /*kotlin.Array*/): S +public fun intersectAfterSmartCast(/*0*/ arg: Base, /*1*/ arg2: Base): kotlin.Any +public fun intersectArgWithSmartCastFromLambda(/*0*/ arg: One, /*1*/ arg2: Base): kotlin.Any +public fun test(): kotlin.Unit + +public interface Base { + public open fun base(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Base2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object O1 : One { + private constructor O1() + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object O2 : Two { + private constructor O2() + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface One : Base, Base2 { + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Two : Base, Base2 { + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAfterSmartCastInLambdaReturn.txt b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAfterSmartCastInLambdaReturn.txt new file mode 100644 index 00000000000..13c9db304f1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAfterSmartCastInLambdaReturn.txt @@ -0,0 +1,50 @@ +package + +public fun argOrFn(/*0*/ arg: S, /*1*/ fn: () -> S): S +public fun intersect(/*0*/ vararg elements: S /*kotlin.Array*/): S +public fun intersectAfterSmartCast(/*0*/ arg: Base, /*1*/ arg2: Base): Base +public fun intersectArgWithSmartCastFromLambda(/*0*/ arg: One, /*1*/ arg2: Base): Base +public fun test(): kotlin.Unit + +public interface Base { + public open fun base(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Base2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object O1 : One { + private constructor O1() + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object O2 : Two { + private constructor O2() + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface One : Base, Base2 { + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Two : Base, Base2 { + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAlternative.fir.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAlternative.fir.kt new file mode 100644 index 00000000000..f138ece7b9b --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAlternative.fir.kt @@ -0,0 +1,17 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER + +interface Bound +interface Bound1 : Bound +interface Bound2 : Bound +interface Bound3 +object First : Bound1, Bound2, Bound3 +object Second : Bound1, Bound2, Bound3 + +fun intersect(vararg elements: S): S where S : Bound1, S : Bound2 = TODO() + +fun testIntersectionAlternative() = intersect(First, Second) + +fun test() { + testIntersectionAlternative() +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAlternative.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAlternative.kt new file mode 100644 index 00000000000..3ff937e8d2f --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAlternative.kt @@ -0,0 +1,17 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER + +interface Bound +interface Bound1 : Bound +interface Bound2 : Bound +interface Bound3 +object First : Bound1, Bound2, Bound3 +object Second : Bound1, Bound2, Bound3 + +fun intersect(vararg elements: S): S where S : Bound1, S : Bound2 = TODO() + +fun testIntersectionAlternative() = intersect(First, Second) + +fun test() { + testIntersectionAlternative() +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAlternative.txt b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAlternative.txt new file mode 100644 index 00000000000..7cbc7b49dbe --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAlternative.txt @@ -0,0 +1,43 @@ +package + +public fun intersect(/*0*/ vararg elements: S /*kotlin.Array*/): S where S : Bound2 +public fun test(): kotlin.Unit +public fun testIntersectionAlternative(): Bound + +public interface Bound { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Bound1 : Bound { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Bound2 : Bound { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Bound3 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object First : Bound1, Bound2, Bound3 { + private constructor First() + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object Second : Bound1, Bound2, Bound3 { + private constructor Second() + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionLocations.fir.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionLocations.fir.kt new file mode 100644 index 00000000000..743999aa99e --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionLocations.fir.kt @@ -0,0 +1,44 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun test() { + testInv() + testIn() + testOut() + testStarProjection() + testErrorType() + testInProjection() + testOutProjection() + testDeeplyNested() +} + +interface Bound1 +interface Bound2 +object First : Bound1, Bound2 +object Second : Bound1, Bound2 + +class Inv(val prop: T) +class Out(val prop: O) +class In(arg: I) +class BiParam(first: F, second: S) + +fun intersect(vararg elements: S): S = TODO() + +fun makeStarProjection(): Inv<*> = TODO() +fun makeInProjection(arg: I): Inv = TODO() +fun makeOutProjection(arg: O): Inv = TODO() +fun testInv() = Inv(intersect(First, Second)) +fun testOut() = Out(intersect(First, Second)) +fun testIn() = In(intersect(First, Second)) +fun testInProjection() = makeInProjection(intersect(First, Second)) +fun testOutProjection() = makeOutProjection(intersect(First, Second)) +fun testDeeplyNested() = Inv(Inv(Inv(intersect(First, Second)))) + +fun testStarProjection() = BiParam( + intersect(First, Second), + makeStarProjection() +) +fun testErrorType() = BiParam( + intersect(First, Second), + unresolved +) diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionLocations.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionLocations.kt new file mode 100644 index 00000000000..62356758c2c --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionLocations.kt @@ -0,0 +1,44 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun test() { + ")!>testInv() + ")!>testIn() + ")!>testOut() + >")!>testStarProjection() + testErrorType() + ")!>testInProjection() + ")!>testOutProjection() + >>")!>testDeeplyNested() +} + +interface Bound1 +interface Bound2 +object First : Bound1, Bound2 +object Second : Bound1, Bound2 + +class Inv(val prop: T) +class Out(val prop: O) +class In(arg: I) +class BiParam(first: F, second: S) + +fun intersect(vararg elements: S): S = TODO() + +fun makeStarProjection(): Inv<*> = TODO() +fun makeInProjection(arg: I): Inv = TODO() +fun makeOutProjection(arg: O): Inv = TODO() +fun testInv() = Inv(intersect(First, Second)) +fun testOut() = Out(intersect(First, Second)) +fun testIn() = In(intersect(First, Second)) +fun testInProjection() = makeInProjection(intersect(First, Second)) +fun testOutProjection() = makeOutProjection(intersect(First, Second)) +fun testDeeplyNested() = Inv(Inv(Inv(intersect(First, Second)))) + +fun testStarProjection() = BiParam( + intersect(First, Second), + makeStarProjection() +) +fun testErrorType() = BiParam( + intersect(First, Second), + unresolved +) diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionLocations.txt b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionLocations.txt new file mode 100644 index 00000000000..b69976ad150 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionLocations.txt @@ -0,0 +1,71 @@ +package + +public fun intersect(/*0*/ vararg elements: S /*kotlin.Array*/): S +public fun makeInProjection(/*0*/ arg: I): Inv +public fun makeOutProjection(/*0*/ arg: O): Inv +public fun makeStarProjection(): Inv<*> +public fun test(): kotlin.Unit +public fun testDeeplyNested(): Inv>> +public fun testErrorType(): [ERROR : Error function type] +public fun testIn(): In +public fun testInProjection(): Inv +public fun testInv(): Inv +public fun testOut(): Out +public fun testOutProjection(): Inv +public fun testStarProjection(): BiParam> + +public final class BiParam { + public constructor BiParam(/*0*/ first: F, /*1*/ second: S) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Bound1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Bound2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object First : Bound1, Bound2 { + private constructor First() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class In { + public constructor In(/*0*/ arg: I) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Inv { + public constructor Inv(/*0*/ prop: T) + public final val prop: T + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Out { + public constructor Out(/*0*/ prop: O) + public final val prop: O + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object Second : Bound1, Bound2 { + private constructor Second() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnArgumentCall.fir.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnArgumentCall.fir.kt new file mode 100644 index 00000000000..7a64a766eea --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnArgumentCall.fir.kt @@ -0,0 +1,19 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +interface First +interface Second + +interface A : First, Second +interface B : First, Second + +fun intersect(vararg elements: S): S = TODO() + +fun runIntersect(arg: A, arg2: A) = run { + if (arg !is B) throw Exception() + if (arg2 !is B) throw Exception() + intersect(arg, arg2) +} + +fun test(arg: A) { + runIntersect(arg, arg) +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnArgumentCall.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnArgumentCall.kt new file mode 100644 index 00000000000..efa5baf94d9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnArgumentCall.kt @@ -0,0 +1,19 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +interface First +interface Second + +interface A : First, Second +interface B : First, Second + +fun intersect(vararg elements: S): S = TODO() + +fun runIntersect(arg: A, arg2: A) = run { + if (arg !is B) throw Exception() + if (arg2 !is B) throw Exception() + intersect(arg, arg2) +} + +fun test(arg: A) { + runIntersect(arg, arg) +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnArgumentCall.txt b/compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnArgumentCall.txt new file mode 100644 index 00000000000..7bf2cf948d5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnArgumentCall.txt @@ -0,0 +1,29 @@ +package + +public fun intersect(/*0*/ vararg elements: S /*kotlin.Array*/): S +public fun runIntersect(/*0*/ arg: A, /*1*/ arg2: A): kotlin.Any +public fun test(/*0*/ arg: A): kotlin.Unit + +public interface A : First, Second { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B : First, Second { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface First { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Second { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnTypeApproximation.fir.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnTypeApproximation.fir.kt new file mode 100644 index 00000000000..880560d6886 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnTypeApproximation.fir.kt @@ -0,0 +1,20 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER + +interface Bound1 +interface Bound2 +object First : Bound1, Bound2 +object Second : Bound1, Bound2 + +fun intersect(vararg elements: S): S = TODO() + +fun run(fn: () -> R): R = TODO() + +fun topLevel() = run { + val local = intersect(First, Second) + local +} + +fun test() { + topLevel() +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnTypeApproximation.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnTypeApproximation.kt new file mode 100644 index 00000000000..5f0119c0aca --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnTypeApproximation.kt @@ -0,0 +1,20 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER + +interface Bound1 +interface Bound2 +object First : Bound1, Bound2 +object Second : Bound1, Bound2 + +fun intersect(vararg elements: S): S = TODO() + +fun run(fn: () -> R): R = TODO() + +fun topLevel() = run { + val local = intersect(First, Second) + local +} + +fun test() { + topLevel() +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnTypeApproximation.txt b/compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnTypeApproximation.txt new file mode 100644 index 00000000000..1173652b426 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnTypeApproximation.txt @@ -0,0 +1,32 @@ +package + +public fun intersect(/*0*/ vararg elements: S /*kotlin.Array*/): S +public fun run(/*0*/ fn: () -> R): R +public fun test(): kotlin.Unit +public fun topLevel(): Bound1 + +public interface Bound1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Bound2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object First : Bound1, Bound2 { + private constructor First() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object Second : Bound1, Bound2 { + private constructor Second() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/nonTrivialVariance.fir.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/nonTrivialVariance.fir.kt new file mode 100644 index 00000000000..eda387ce8bc --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/nonTrivialVariance.fir.kt @@ -0,0 +1,54 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun test(first: First, second: Second) { + test1(first, second) + test2(first, second) + test3(first, second) + test4(first, second) + test5(first, second) + test6(first, second) + test7(first, second) + test8(first, second) + test9(first, second) + + test10(first, second) + test11(first, second) + test12(first, second) + test13(first, second) + test14(first, second) + test15(first, second) + test16(first, second) + test17(first, second) + test18(first, second) +} + +interface Bound1 +interface Bound2 +object First : Bound1, Bound2 +object Second : Bound1, Bound2 + +fun intersect(vararg elements: S): S = TODO() + +class Inv(val prop: T) +class In(arg: I) +class Out(val arg: O) + +fun test1(first: First, second: Second) = Inv(Inv(intersect(first, second))) +fun test2(first: First, second: Second) = Inv(In(intersect(first, second))) +fun test3(first: First, second: Second) = Inv(Out(intersect(first, second))) +fun test4(first: First, second: Second) = In(Inv(intersect(first, second))) +fun test5(first: First, second: Second) = In(In(intersect(first, second))) +fun test6(first: First, second: Second) = In(Out(intersect(first, second))) +fun test7(first: First, second: Second) = Out(Inv(intersect(first, second))) +fun test8(first: First, second: Second) = Out(In(intersect(first, second))) +fun test9(first: First, second: Second) = Out(Out(intersect(first, second))) + +fun test10(first: First, second: Second) = Out(Out(Out(intersect(first, second)))) +fun test11(first: First, second: Second) = Inv(Out(Out(intersect(first, second)))) +fun test12(first: First, second: Second) = Inv(Out(In(intersect(first, second)))) +fun test13(first: First, second: Second) = Inv(In(Out(intersect(first, second)))) +fun test14(first: First, second: Second) = Inv(In(In(intersect(first, second)))) +fun test15(first: First, second: Second) = Out(Inv(Out(intersect(first, second)))) +fun test16(first: First, second: Second) = Out(Out(In(intersect(first, second)))) +fun test17(first: First, second: Second) = Out(In(Out(intersect(first, second)))) +fun test18(first: First, second: Second) = In(Out(Out(intersect(first, second)))) diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/nonTrivialVariance.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/nonTrivialVariance.kt new file mode 100644 index 00000000000..3b3428e74d7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/nonTrivialVariance.kt @@ -0,0 +1,54 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun test(first: First, second: Second) { + >")!>test1(first, second) + >")!>test2(first, second) + >")!>test3(first, second) + >")!>test4(first, second) + >")!>test5(first, second) + >")!>test6(first, second) + >")!>test7(first, second) + >")!>test8(first, second) + >")!>test9(first, second) + + >>")!>test10(first, second) + >>")!>test11(first, second) + >>")!>test12(first, second) + >>")!>test13(first, second) + >>")!>test14(first, second) + >>")!>test15(first, second) + >>")!>test16(first, second) + >>")!>test17(first, second) + >>")!>test18(first, second) +} + +interface Bound1 +interface Bound2 +object First : Bound1, Bound2 +object Second : Bound1, Bound2 + +fun intersect(vararg elements: S): S = TODO() + +class Inv(val prop: T) +class In(arg: I) +class Out(val arg: O) + +fun test1(first: First, second: Second) = Inv(Inv(intersect(first, second))) +fun test2(first: First, second: Second) = Inv(In(intersect(first, second))) +fun test3(first: First, second: Second) = Inv(Out(intersect(first, second))) +fun test4(first: First, second: Second) = In(Inv(intersect(first, second))) +fun test5(first: First, second: Second) = In(In(intersect(first, second))) +fun test6(first: First, second: Second) = In(Out(intersect(first, second))) +fun test7(first: First, second: Second) = Out(Inv(intersect(first, second))) +fun test8(first: First, second: Second) = Out(In(intersect(first, second))) +fun test9(first: First, second: Second) = Out(Out(intersect(first, second))) + +fun test10(first: First, second: Second) = Out(Out(Out(intersect(first, second)))) +fun test11(first: First, second: Second) = Inv(Out(Out(intersect(first, second)))) +fun test12(first: First, second: Second) = Inv(Out(In(intersect(first, second)))) +fun test13(first: First, second: Second) = Inv(In(Out(intersect(first, second)))) +fun test14(first: First, second: Second) = Inv(In(In(intersect(first, second)))) +fun test15(first: First, second: Second) = Out(Inv(Out(intersect(first, second)))) +fun test16(first: First, second: Second) = Out(Out(In(intersect(first, second)))) +fun test17(first: First, second: Second) = Out(In(Out(intersect(first, second)))) +fun test18(first: First, second: Second) = In(Out(Out(intersect(first, second)))) diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/nonTrivialVariance.txt b/compiler/testData/diagnostics/tests/inference/publicApproximation/nonTrivialVariance.txt new file mode 100644 index 00000000000..1db0a5b1490 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/nonTrivialVariance.txt @@ -0,0 +1,71 @@ +package + +public fun intersect(/*0*/ vararg elements: S /*kotlin.Array*/): S +public fun test(/*0*/ first: First, /*1*/ second: Second): kotlin.Unit +public fun test1(/*0*/ first: First, /*1*/ second: Second): Inv> +public fun test10(/*0*/ first: First, /*1*/ second: Second): Out>> +public fun test11(/*0*/ first: First, /*1*/ second: Second): Inv>> +public fun test12(/*0*/ first: First, /*1*/ second: Second): Inv>> +public fun test13(/*0*/ first: First, /*1*/ second: Second): Inv>> +public fun test14(/*0*/ first: First, /*1*/ second: Second): Inv>> +public fun test15(/*0*/ first: First, /*1*/ second: Second): Out>> +public fun test16(/*0*/ first: First, /*1*/ second: Second): Out>> +public fun test17(/*0*/ first: First, /*1*/ second: Second): Out>> +public fun test18(/*0*/ first: First, /*1*/ second: Second): In>> +public fun test2(/*0*/ first: First, /*1*/ second: Second): Inv> +public fun test3(/*0*/ first: First, /*1*/ second: Second): Inv> +public fun test4(/*0*/ first: First, /*1*/ second: Second): In> +public fun test5(/*0*/ first: First, /*1*/ second: Second): In> +public fun test6(/*0*/ first: First, /*1*/ second: Second): In> +public fun test7(/*0*/ first: First, /*1*/ second: Second): Out> +public fun test8(/*0*/ first: First, /*1*/ second: Second): Out> +public fun test9(/*0*/ first: First, /*1*/ second: Second): Out> + +public interface Bound1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Bound2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object First : Bound1, Bound2 { + private constructor First() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class In { + public constructor In(/*0*/ arg: I) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Inv { + public constructor Inv(/*0*/ prop: T) + public final val prop: T + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Out { + public constructor Out(/*0*/ arg: O) + public final val arg: O + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object Second : Bound1, Bound2 { + private constructor Second() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/parameterInBound.fir.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/parameterInBound.fir.kt new file mode 100644 index 00000000000..b07f41e784e --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/parameterInBound.fir.kt @@ -0,0 +1,25 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER + +interface Bound1 +interface Bound2 +object First : Bound1, Bound2 +object Second : Bound1, Bound2 + +interface WithParam1 +interface WithParam2 +class ClsWithParam1 : WithParam1, WithParam2 +class ClsWithParam2 : WithParam1, WithParam2 + +fun intersect(vararg elements: S): S = TODO() +fun > combineParams(first: T, vararg args: P): P = TODO() + +fun topLevel() = combineParams( + intersect(First, Second), + ClsWithParam1(), + ClsWithParam2() +) + +fun test() { + topLevel() +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/parameterInBound.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/parameterInBound.kt new file mode 100644 index 00000000000..8f18cb6376f --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/parameterInBound.kt @@ -0,0 +1,25 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER + +interface Bound1 +interface Bound2 +object First : Bound1, Bound2 +object Second : Bound1, Bound2 + +interface WithParam1 +interface WithParam2 +class ClsWithParam1 : WithParam1, WithParam2 +class ClsWithParam2 : WithParam1, WithParam2 + +fun intersect(vararg elements: S): S = TODO() +fun > combineParams(first: T, vararg args: P): P = TODO() + +fun topLevel() = & WithParam2<{Bound1 & Bound2}>}")!>combineParams( + intersect(First, Second), + ClsWithParam1(), + ClsWithParam2() +) + +fun test() { + ")!>topLevel() +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/parameterInBound.txt b/compiler/testData/diagnostics/tests/inference/publicApproximation/parameterInBound.txt new file mode 100644 index 00000000000..5db6b3159f7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/parameterInBound.txt @@ -0,0 +1,58 @@ +package + +public fun > combineParams(/*0*/ first: T, /*1*/ vararg args: P /*kotlin.Array*/): P +public fun intersect(/*0*/ vararg elements: S /*kotlin.Array*/): S +public fun test(): kotlin.Unit +public fun topLevel(): WithParam1 + +public interface Bound1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Bound2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class ClsWithParam1 : WithParam1, WithParam2 { + public constructor ClsWithParam1() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class ClsWithParam2 : WithParam1, WithParam2 { + public constructor ClsWithParam2() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object First : Bound1, Bound2 { + private constructor First() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object Second : Bound1, Bound2 { + private constructor Second() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface WithParam1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface WithParam2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/projections.fir.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/projections.fir.kt new file mode 100644 index 00000000000..22aaed4058a --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/projections.fir.kt @@ -0,0 +1,19 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +interface Bound1 +interface Bound2 +object First : Bound1, Bound2 +object Second : Bound1, Bound2 + +class Inv + +fun makeOut(vararg args: O): Inv = TODO() +fun makeIn(vararg args: I): Inv = TODO() + +fun testOut() = makeOut(First, Second) +fun testIn() = makeIn(First, Second) + +fun test() { + testOut() + testIn() +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/projections.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/projections.kt new file mode 100644 index 00000000000..8f1856bd7c9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/projections.kt @@ -0,0 +1,19 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +interface Bound1 +interface Bound2 +object First : Bound1, Bound2 +object Second : Bound1, Bound2 + +class Inv + +fun makeOut(vararg args: O): Inv = TODO() +fun makeIn(vararg args: I): Inv = TODO() + +fun testOut() = makeOut(First, Second) +fun testIn() = makeIn(First, Second) + +fun test() { + ")!>testOut() + ")!>testIn() +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/projections.txt b/compiler/testData/diagnostics/tests/inference/publicApproximation/projections.txt new file mode 100644 index 00000000000..9c1c30d9887 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/projections.txt @@ -0,0 +1,40 @@ +package + +public fun makeIn(/*0*/ vararg args: I /*kotlin.Array*/): Inv +public fun makeOut(/*0*/ vararg args: O /*kotlin.Array*/): Inv +public fun test(): kotlin.Unit +public fun testIn(): Inv +public fun testOut(): Inv + +public interface Bound1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Bound2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object First : Bound1, Bound2 { + private constructor First() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Inv { + public constructor Inv() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object Second : Bound1, Bound2 { + private constructor Second() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/smartCastInLambdaReturnAfterIntersection.fir.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/smartCastInLambdaReturnAfterIntersection.fir.kt new file mode 100644 index 00000000000..e03f91c740c --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/smartCastInLambdaReturnAfterIntersection.fir.kt @@ -0,0 +1,22 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !WITH_NEW_INFERENCE +// NI_EXPECTED_FILE + +interface Base { + fun base() {} +} +interface Base2 +interface One : Base, Base2 +interface Two : Base, Base2 + +fun intersectNullable(vararg elements: S): S? = TODO() + +fun smartCastAfterIntersection(a: One, b: Two) = run { + val v = intersectNullable(a, b) + if (v == null) throw Exception() + v +} + +fun test(one: One, two: Two) { + smartCastAfterIntersection(one, two)?.base() +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/smartCastInLambdaReturnAfterIntersection.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/smartCastInLambdaReturnAfterIntersection.kt new file mode 100644 index 00000000000..42665f9e35b --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/smartCastInLambdaReturnAfterIntersection.kt @@ -0,0 +1,22 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !WITH_NEW_INFERENCE +// NI_EXPECTED_FILE + +interface Base { + fun base() {} +} +interface Base2 +interface One : Base, Base2 +interface Two : Base, Base2 + +fun intersectNullable(vararg elements: S): S? = TODO() + +fun smartCastAfterIntersection(a: One, b: Two) = run { + val v = intersectNullable(a, b) + if (v == null) throw Exception() + v +} + +fun test(one: One, two: Two) { + smartCastAfterIntersection(one, two)?.base() +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/smartCastInLambdaReturnAfterIntersection.ni.txt b/compiler/testData/diagnostics/tests/inference/publicApproximation/smartCastInLambdaReturnAfterIntersection.ni.txt new file mode 100644 index 00000000000..0b55f6a01bf --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/smartCastInLambdaReturnAfterIntersection.ni.txt @@ -0,0 +1,32 @@ +package + +public fun intersectNullable(/*0*/ vararg elements: S /*kotlin.Array*/): S? +public fun smartCastAfterIntersection(/*0*/ a: One, /*1*/ b: Two): kotlin.Any +public fun test(/*0*/ one: One, /*1*/ two: Two): kotlin.Unit + +public interface Base { + public open fun base(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Base2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface One : Base, Base2 { + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Two : Base, Base2 { + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/smartCastInLambdaReturnAfterIntersection.txt b/compiler/testData/diagnostics/tests/inference/publicApproximation/smartCastInLambdaReturnAfterIntersection.txt new file mode 100644 index 00000000000..727f67e6077 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/smartCastInLambdaReturnAfterIntersection.txt @@ -0,0 +1,32 @@ +package + +public fun intersectNullable(/*0*/ vararg elements: S /*kotlin.Array*/): S? +public fun smartCastAfterIntersection(/*0*/ a: One, /*1*/ b: Two): Base? +public fun test(/*0*/ one: One, /*1*/ two: Two): kotlin.Unit + +public interface Base { + public open fun base(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Base2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface One : Base, Base2 { + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Two : Base, Base2 { + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/twoIntersections.fir.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/twoIntersections.fir.kt new file mode 100644 index 00000000000..61df54f8734 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/twoIntersections.fir.kt @@ -0,0 +1,25 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !WITH_NEW_INFERENCE +// NI_EXPECTED_FILE + +interface Base { + fun base() {} +} +interface Base2 : Base3 +interface Base3 +interface One : Base, Base2 +interface Two : Base, Base2 +interface Three : Base, Base3 + +object O1 : One +object O2 : Two +object O3 : Three + +fun intersect(vararg elements: S): S = TODO() +fun intersectNoBound(vararg elements: S): S = TODO() + +fun some(a: One, b: Two, c: Three) = intersectNoBound(intersect(a, b), c) + +fun test(arg: Base, arg2: Base) { + some(O1, O2, O3).base() +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/twoIntersections.kt b/compiler/testData/diagnostics/tests/inference/publicApproximation/twoIntersections.kt new file mode 100644 index 00000000000..c9260062a90 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/twoIntersections.kt @@ -0,0 +1,25 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !WITH_NEW_INFERENCE +// NI_EXPECTED_FILE + +interface Base { + fun base() {} +} +interface Base2 : Base3 +interface Base3 +interface One : Base, Base2 +interface Two : Base, Base2 +interface Three : Base, Base3 + +object O1 : One +object O2 : Two +object O3 : Three + +fun intersect(vararg elements: S): S = TODO() +fun intersectNoBound(vararg elements: S): S = TODO() + +fun some(a: One, b: Two, c: Three) = intersectNoBound(intersect(a, b), c) + +fun test(arg: Base, arg2: Base) { + some(O1, O2, O3).base() +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/twoIntersections.ni.txt b/compiler/testData/diagnostics/tests/inference/publicApproximation/twoIntersections.ni.txt new file mode 100644 index 00000000000..59a76520fa7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/twoIntersections.ni.txt @@ -0,0 +1,70 @@ +package + +public fun intersect(/*0*/ vararg elements: S /*kotlin.Array*/): S +public fun intersectNoBound(/*0*/ vararg elements: S /*kotlin.Array*/): S +public fun some(/*0*/ a: One, /*1*/ b: Two, /*2*/ c: Three): kotlin.Any +public fun test(/*0*/ arg: Base, /*1*/ arg2: Base): kotlin.Unit + +public interface Base { + public open fun base(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Base2 : Base3 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Base3 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object O1 : One { + private constructor O1() + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object O2 : Two { + private constructor O2() + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object O3 : Three { + private constructor O3() + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface One : Base, Base2 { + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Three : Base, Base3 { + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Two : Base, Base2 { + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/publicApproximation/twoIntersections.txt b/compiler/testData/diagnostics/tests/inference/publicApproximation/twoIntersections.txt new file mode 100644 index 00000000000..6e6e7af89e9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/publicApproximation/twoIntersections.txt @@ -0,0 +1,70 @@ +package + +public fun intersect(/*0*/ vararg elements: S /*kotlin.Array*/): S +public fun intersectNoBound(/*0*/ vararg elements: S /*kotlin.Array*/): S +public fun some(/*0*/ a: One, /*1*/ b: Two, /*2*/ c: Three): Base +public fun test(/*0*/ arg: Base, /*1*/ arg2: Base): kotlin.Unit + +public interface Base { + public open fun base(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Base2 : Base3 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Base3 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object O1 : One { + private constructor O1() + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object O2 : Two { + private constructor O2() + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object O3 : Three { + private constructor O3() + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface One : Base, Base2 { + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Three : Base, Base3 { + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Two : Base, Base2 { + public open override /*1*/ /*fake_override*/ fun base(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/topLevelIntersection.fir.kt b/compiler/testData/diagnostics/tests/inference/topLevelIntersection.fir.kt new file mode 100644 index 00000000000..15fae639ee4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/topLevelIntersection.fir.kt @@ -0,0 +1,17 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -UNUSED_EXPRESSION + +interface Bound1 +interface Bound2 +object First : Bound1, Bound2 +object Second : Bound1, Bound2 + +fun select(vararg args: S): S = TODO() + +class Cls { + val property = select(First, Second) +} + +fun test() { + val v = Cls().property + v +} diff --git a/compiler/testData/diagnostics/tests/inference/topLevelIntersection.kt b/compiler/testData/diagnostics/tests/inference/topLevelIntersection.kt new file mode 100644 index 00000000000..20df5822ae4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/topLevelIntersection.kt @@ -0,0 +1,17 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -UNUSED_EXPRESSION + +interface Bound1 +interface Bound2 +object First : Bound1, Bound2 +object Second : Bound1, Bound2 + +fun select(vararg args: S): S = TODO() + +class Cls { + val property = select(First, Second) +} + +fun test() { + val v = Cls().property + v +} diff --git a/compiler/testData/diagnostics/tests/inference/topLevelIntersection.txt b/compiler/testData/diagnostics/tests/inference/topLevelIntersection.txt new file mode 100644 index 00000000000..60e99d2858c --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/topLevelIntersection.txt @@ -0,0 +1,38 @@ +package + +public fun select(/*0*/ vararg args: S /*kotlin.Array*/): S +public fun test(): kotlin.Unit + +public interface Bound1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Bound2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Cls { + public constructor Cls() + public final val property: Bound1 + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object First : Bound1, Bound2 { + private constructor First() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object Second : Bound1, Bound2 { + private constructor Second() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorTypeArgumentsInferenceWithNestedCalls.ni.txt b/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorTypeArgumentsInferenceWithNestedCalls.ni.txt index c09d0cb8f26..2b3f9d79b85 100644 --- a/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorTypeArgumentsInferenceWithNestedCalls.ni.txt +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorTypeArgumentsInferenceWithNestedCalls.ni.txt @@ -1,7 +1,7 @@ package public val test1: C /* = Cons */ -public val test2: Cons +public val test2: C /* = Cons */ public final class Cons { public constructor Cons(/*0*/ head: T, /*1*/ tail: Cons?) diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/kt36249.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/kt36249.fir.kt new file mode 100644 index 00000000000..933682a0710 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/kt36249.fir.kt @@ -0,0 +1,18 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER UNUSED_VARIABLE -UNUSED_EXPRESSION + +import kotlin.reflect.KClass +fun select(vararg classes: KClass): T? { + return null +} +interface PomRenameableTarget +interface PsiElement +interface PsiMethod : PsiElement, PomRenameableTarget +interface PsiClass : PsiElement, PomRenameableTarget + +class A { + val inv get() = select(PsiMethod::class, PsiClass::class) +} + +fun main() { + A().inv +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/kt36249.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/kt36249.kt new file mode 100644 index 00000000000..67227acfb08 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/kt36249.kt @@ -0,0 +1,18 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER UNUSED_VARIABLE -UNUSED_EXPRESSION + +import kotlin.reflect.KClass +fun select(vararg classes: KClass): T? { + return null +} +interface PomRenameableTarget +interface PsiElement +interface PsiMethod : PsiElement, PomRenameableTarget +interface PsiClass : PsiElement, PomRenameableTarget + +class A { + val inv get() = select(PsiMethod::class, PsiClass::class) +} + +fun main() { + A().inv +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/kt36249.txt b/compiler/testData/diagnostics/testsWithStdLib/inference/kt36249.txt new file mode 100644 index 00000000000..d474325c4b4 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/kt36249.txt @@ -0,0 +1,36 @@ +package + +public fun main(): kotlin.Unit +public fun select(/*0*/ vararg classes: kotlin.reflect.KClass /*kotlin.Array>*/): T? + +public final class A { + public constructor A() + public final val inv: PsiElement? + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface PomRenameableTarget { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface PsiClass : PsiElement, PomRenameableTarget { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface PsiElement { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface PsiMethod : PsiElement, PomRenameableTarget { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/ir/irText/expressions/implicitCastToTypeParameter.txt b/compiler/testData/ir/irText/expressions/implicitCastToTypeParameter.txt index 0ffed6ae349..fff76479eb2 100644 --- a/compiler/testData/ir/irText/expressions/implicitCastToTypeParameter.txt +++ b/compiler/testData/ir/irText/expressions/implicitCastToTypeParameter.txt @@ -36,15 +36,15 @@ FILE fqName: fileName:/implicitCastToTypeParameter.kt $receiver: VALUE_PARAMETER name: type:.Foo.> BLOCK_BODY RETURN type=kotlin.Nothing from='public final fun (): T of .? [inline] declared in ' - TYPE_OP type=T of .? origin=IMPLICIT_CAST typeOperand=T of .? - WHEN type=kotlin.Any? origin=IF - BRANCH - if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=T of . - GET_VAR ': .Foo.> declared in .' type=.Foo.> origin=null - then: GET_VAR ': .Foo.> declared in .' type=.Foo.> origin=null - BRANCH - if: CONST Boolean type=kotlin.Boolean value=true - then: CONST Null type=kotlin.Nothing? value=null + WHEN type=T of .? origin=IF + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=T of . + GET_VAR ': .Foo.> declared in .' type=.Foo.> origin=null + then: TYPE_OP type=T of . origin=IMPLICIT_CAST typeOperand=T of . + GET_VAR ': .Foo.> declared in .' type=.Foo.> origin=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CONST Null type=kotlin.Nothing? value=null CLASS CLASS name:Bar modality:FINAL visibility:public superTypes:[kotlin.Any] $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.Bar.Bar> TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index b7b924b69e6..9aa24574e2c 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -10233,6 +10233,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali runTest("compiler/testData/diagnostics/tests/inference/tooEagerSmartcast.kt"); } + @TestMetadata("topLevelIntersection.kt") + public void testTopLevelIntersection() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/topLevelIntersection.kt"); + } + @TestMetadata("tryNumberLowerBoundsBeforeUpperBounds.kt") public void testTryNumberLowerBoundsBeforeUpperBounds() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/tryNumberLowerBoundsBeforeUpperBounds.kt"); @@ -11029,6 +11034,84 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali } } + @TestMetadata("compiler/testData/diagnostics/tests/inference/publicApproximation") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class PublicApproximation extends AbstractDiagnosticsTestWithFirValidation { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInPublicApproximation() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/publicApproximation"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @TestMetadata("approximatedIntersectionMorePreciseThanBound.kt") + public void testApproximatedIntersectionMorePreciseThanBound() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/approximatedIntersectionMorePreciseThanBound.kt"); + } + + @TestMetadata("chainedLambdas.kt") + public void testChainedLambdas() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/chainedLambdas.kt"); + } + + @TestMetadata("declarationTypes.kt") + public void testDeclarationTypes() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/declarationTypes.kt"); + } + + @TestMetadata("intersectionAfterSmartCastInLambdaReturn.kt") + public void testIntersectionAfterSmartCastInLambdaReturn() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAfterSmartCastInLambdaReturn.kt"); + } + + @TestMetadata("intersectionAlternative.kt") + public void testIntersectionAlternative() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAlternative.kt"); + } + + @TestMetadata("intersectionLocations.kt") + public void testIntersectionLocations() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionLocations.kt"); + } + + @TestMetadata("lambdaReturnArgumentCall.kt") + public void testLambdaReturnArgumentCall() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnArgumentCall.kt"); + } + + @TestMetadata("lambdaReturnTypeApproximation.kt") + public void testLambdaReturnTypeApproximation() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnTypeApproximation.kt"); + } + + @TestMetadata("nonTrivialVariance.kt") + public void testNonTrivialVariance() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/nonTrivialVariance.kt"); + } + + @TestMetadata("parameterInBound.kt") + public void testParameterInBound() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/parameterInBound.kt"); + } + + @TestMetadata("projections.kt") + public void testProjections() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/projections.kt"); + } + + @TestMetadata("smartCastInLambdaReturnAfterIntersection.kt") + public void testSmartCastInLambdaReturnAfterIntersection() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/smartCastInLambdaReturnAfterIntersection.kt"); + } + + @TestMetadata("twoIntersections.kt") + public void testTwoIntersections() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/twoIntersections.kt"); + } + } + @TestMetadata("compiler/testData/diagnostics/tests/inference/recursiveCalls") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index 95427eef8ae..10ffbe731cd 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -2881,6 +2881,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW runTest("compiler/testData/diagnostics/testsWithStdLib/inference/kt35847.kt"); } + @TestMetadata("kt36249.kt") + public void testKt36249() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/kt36249.kt"); + } + @TestMetadata("kt4975.kt") public void testKt4975() throws Exception { runTest("compiler/testData/diagnostics/testsWithStdLib/inference/kt4975.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java index 38735cc15fe..eda919f8a67 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java @@ -2881,6 +2881,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno runTest("compiler/testData/diagnostics/testsWithStdLib/inference/kt35847.kt"); } + @TestMetadata("kt36249.kt") + public void testKt36249() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/kt36249.kt"); + } + @TestMetadata("kt4975.kt") public void testKt4975() throws Exception { runTest("compiler/testData/diagnostics/testsWithStdLib/inference/kt4975.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 59132defe83..30f30d15932 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -10228,6 +10228,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/inference/tooEagerSmartcast.kt"); } + @TestMetadata("topLevelIntersection.kt") + public void testTopLevelIntersection() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/topLevelIntersection.kt"); + } + @TestMetadata("tryNumberLowerBoundsBeforeUpperBounds.kt") public void testTryNumberLowerBoundsBeforeUpperBounds() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/tryNumberLowerBoundsBeforeUpperBounds.kt"); @@ -11024,6 +11029,84 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing } } + @TestMetadata("compiler/testData/diagnostics/tests/inference/publicApproximation") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class PublicApproximation extends AbstractDiagnosticsUsingJavacTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInPublicApproximation() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/publicApproximation"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @TestMetadata("approximatedIntersectionMorePreciseThanBound.kt") + public void testApproximatedIntersectionMorePreciseThanBound() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/approximatedIntersectionMorePreciseThanBound.kt"); + } + + @TestMetadata("chainedLambdas.kt") + public void testChainedLambdas() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/chainedLambdas.kt"); + } + + @TestMetadata("declarationTypes.kt") + public void testDeclarationTypes() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/declarationTypes.kt"); + } + + @TestMetadata("intersectionAfterSmartCastInLambdaReturn.kt") + public void testIntersectionAfterSmartCastInLambdaReturn() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAfterSmartCastInLambdaReturn.kt"); + } + + @TestMetadata("intersectionAlternative.kt") + public void testIntersectionAlternative() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionAlternative.kt"); + } + + @TestMetadata("intersectionLocations.kt") + public void testIntersectionLocations() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/intersectionLocations.kt"); + } + + @TestMetadata("lambdaReturnArgumentCall.kt") + public void testLambdaReturnArgumentCall() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnArgumentCall.kt"); + } + + @TestMetadata("lambdaReturnTypeApproximation.kt") + public void testLambdaReturnTypeApproximation() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/lambdaReturnTypeApproximation.kt"); + } + + @TestMetadata("nonTrivialVariance.kt") + public void testNonTrivialVariance() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/nonTrivialVariance.kt"); + } + + @TestMetadata("parameterInBound.kt") + public void testParameterInBound() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/parameterInBound.kt"); + } + + @TestMetadata("projections.kt") + public void testProjections() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/projections.kt"); + } + + @TestMetadata("smartCastInLambdaReturnAfterIntersection.kt") + public void testSmartCastInLambdaReturnAfterIntersection() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/smartCastInLambdaReturnAfterIntersection.kt"); + } + + @TestMetadata("twoIntersections.kt") + public void testTwoIntersections() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/publicApproximation/twoIntersections.kt"); + } + } + @TestMetadata("compiler/testData/diagnostics/tests/inference/recursiveCalls") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/IntersectionTypeConstructor.kt b/core/descriptors/src/org/jetbrains/kotlin/types/IntersectionTypeConstructor.kt index a5871b9b762..a80a40ab20b 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/IntersectionTypeConstructor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/IntersectionTypeConstructor.kt @@ -27,6 +27,15 @@ import org.jetbrains.kotlin.types.refinement.TypeRefinement import java.util.* class IntersectionTypeConstructor(typesToIntersect: Collection) : TypeConstructor { + private var alternative: KotlinType? = null + + private constructor( + typesToIntersect: Collection, + alternative: KotlinType?, + ) : this(typesToIntersect) { + this.alternative = alternative + } + init { assert(!typesToIntersect.isEmpty()) { "Attempt to create an empty intersection" } } @@ -75,7 +84,13 @@ class IntersectionTypeConstructor(typesToIntersect: Collection) : Ty @TypeRefinement override fun refine(kotlinTypeRefiner: KotlinTypeRefiner) = - IntersectionTypeConstructor(intersectedTypes.map { it.refine(kotlinTypeRefiner) }) + transformComponents { it.refine(kotlinTypeRefiner) } ?: this + + fun setAlternative(alternative: KotlinType?): IntersectionTypeConstructor { + return IntersectionTypeConstructor(intersectedTypes, alternative) + } + + fun getAlternativeType(): KotlinType? = alternative } inline fun IntersectionTypeConstructor.transformComponents( @@ -94,5 +109,9 @@ inline fun IntersectionTypeConstructor.transformComponents( if (!changed) return null - return IntersectionTypeConstructor(newSupertypes) + val updatedAlternative = getAlternativeType()?.let { alternative -> + if (predicate(alternative)) transform(alternative) else alternative + } + + return IntersectionTypeConstructor(newSupertypes).setAlternative(updatedAlternative) } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt index 6a8140ed99d..406396a66cf 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.types.model.* import org.jetbrains.kotlin.types.typeUtil.asTypeProjection import org.jetbrains.kotlin.types.typeUtil.contains import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound +import org.jetbrains.kotlin.utils.addToStdlib.safeAs import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract @@ -606,6 +607,21 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy val descriptor = constructor.declarationDescriptor return descriptor is ClassDescriptor && (descriptor.kind == ClassKind.INTERFACE || descriptor.kind == ClassKind.ANNOTATION_CLASS) } + + override fun createTypeWithAlternativeForIntersectionResult( + firstCandidate: KotlinTypeMarker, + secondCandidate: KotlinTypeMarker, + ): KotlinTypeMarker { + require(firstCandidate is KotlinType, this::errorMessage) + require(secondCandidate is KotlinType, this::errorMessage) + + firstCandidate.constructor.safeAs()?.let { intersectionConstructor -> + val intersectionTypeWithAlternative = intersectionConstructor.setAlternative(secondCandidate).createType() + return if (firstCandidate.isMarkedNullable) intersectionTypeWithAlternative.makeNullableAsSpecified(true) + else intersectionTypeWithAlternative + + } ?: error("Expected intersection type, found $firstCandidate") + } } fun TypeVariance.convertVariance(): Variance { diff --git a/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt b/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt index 831cf847684..c39abedd766 100644 --- a/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt +++ b/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt @@ -164,6 +164,11 @@ interface TypeSystemInferenceExtensionContext : TypeSystemContext, TypeSystemBui fun TypeVariableMarker.defaultType(): SimpleTypeMarker + + fun createTypeWithAlternativeForIntersectionResult( + firstCandidate: KotlinTypeMarker, + secondCandidate: KotlinTypeMarker + ): KotlinTypeMarker }