diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index 808e1c71be3..fbf4c11121a 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -11937,6 +11937,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/inference/regressions/kt38691.kt"); } + @TestMetadata("kt41386.kt") + public void testKt41386() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/regressions/kt41386.kt"); + } + @TestMetadata("kt4420.kt") public void testKt4420() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/regressions/kt4420.kt"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt index efe8885fb2f..8750da26e65 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt @@ -30,7 +30,6 @@ import org.jetbrains.kotlin.resolve.calls.inference.buildResultingSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutorByConstructorMap -import org.jetbrains.kotlin.resolve.calls.inference.components.composeWith import org.jetbrains.kotlin.resolve.calls.inference.model.* import org.jetbrains.kotlin.resolve.calls.inference.substitute import org.jetbrains.kotlin.resolve.calls.inference.substituteAndApproximateTypes @@ -809,10 +808,10 @@ class NewResolvedCallImpl( shouldApproximate: Boolean = true ): CallableDescriptor { val inferredTypeVariablesSubstitutor = substitutor ?: FreshVariableNewTypeSubstitutor.Empty - val compositeSubstitutor = inferredTypeVariablesSubstitutor.composeWith(resolvedCallAtom.knownParametersSubstitutor) - return substitute(resolvedCallAtom.freshVariablesSubstitutor) - .substituteAndApproximateTypes(compositeSubstitutor, if (shouldApproximate) typeApproximator else null) + // TODO: merge last two substitutors to avoid redundant descriptor substitutions + return substitute(resolvedCallAtom.freshVariablesSubstitutor).substitute(resolvedCallAtom.knownParametersSubstitutor) + .substituteAndApproximateTypes(inferredTypeVariablesSubstitutor, if (shouldApproximate) typeApproximator else null) } fun getArgumentTypeForConstantConvertedArgument(valueArgument: ValueArgument): IntegerValueTypeConstant? { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt index c1ee1c79eea..acc53f2b50f 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt @@ -12,7 +12,7 @@ import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper.TypeArgumentsMapping.NoExplicitArguments import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem -import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor +import org.jetbrains.kotlin.resolve.calls.inference.components.* import org.jetbrains.kotlin.resolve.calls.inference.model.* import org.jetbrains.kotlin.resolve.calls.inference.substitute import org.jetbrains.kotlin.resolve.calls.model.* @@ -115,14 +115,22 @@ internal object NoArguments : ResolutionPart() { internal object CreateFreshVariablesSubstitutor : ResolutionPart() { override fun KotlinResolutionCandidate.process(workIndex: Int) { - resolvedCall.knownParametersSubstitutor = knownTypeParametersResultingSubstitutor ?: TypeSubstitutor.EMPTY + val toFreshVariables = + if (candidateDescriptor.typeParameters.isEmpty()) + FreshVariableNewTypeSubstitutor.Empty + else + createToFreshVariableSubstitutorAndAddInitialConstraints(candidateDescriptor, csBuilder) + + val knownTypeParametersSubstitutor = knownTypeParametersResultingSubstitutor?.let { + createKnownParametersFromFreshVariablesSubstitutor(toFreshVariables, knownTypeParametersResultingSubstitutor) + } ?: EmptySubstitutor + + resolvedCall.freshVariablesSubstitutor = toFreshVariables + resolvedCall.knownParametersSubstitutor = knownTypeParametersSubstitutor if (candidateDescriptor.typeParameters.isEmpty()) { - resolvedCall.freshVariablesSubstitutor = FreshVariableNewTypeSubstitutor.Empty return } - val toFreshVariables = createToFreshVariableSubstitutorAndAddInitialConstraints(candidateDescriptor, csBuilder) - resolvedCall.freshVariablesSubstitutor = toFreshVariables // bad function -- error on declaration side if (csBuilder.hasContradiction) return @@ -176,6 +184,27 @@ internal object CreateFreshVariablesSubstitutor : ResolutionPart() { KotlinTypeFactory.flexibleType(type.makeNotNullable().lowerIfFlexible(), type.makeNullable().upperIfFlexible()) } else type + private fun createKnownParametersFromFreshVariablesSubstitutor( + freshVariableSubstitutor: FreshVariableNewTypeSubstitutor, + knownTypeParametersSubstitutor: TypeSubstitutor, + ): NewTypeSubstitutor { + if (knownTypeParametersSubstitutor.isEmpty) + return EmptySubstitutor + + val knownTypeParameterByTypeVariable = mutableMapOf().let { map -> + for (typeVariable in freshVariableSubstitutor.freshVariables) { + val typeParameterType = typeVariable.originalTypeParameter.defaultType + val substitutedKnownTypeParameter = knownTypeParametersSubstitutor.substitute(typeParameterType) + + if (substitutedKnownTypeParameter !== typeParameterType) + map[typeVariable.defaultType.constructor] = substitutedKnownTypeParameter + } + map + } + + return knownTypeParametersSubstitutor.composeWith(NewTypeSubstitutorByConstructorMap(knownTypeParameterByTypeVariable)) + } + fun createToFreshVariableSubstitutorAndAddInitialConstraints( candidateDescriptor: CallableDescriptor, csBuilder: ConstraintSystemOperation @@ -595,8 +624,8 @@ private fun KotlinResolutionCandidate.checkUnsafeImplicitInvokeAfterSafeCall(arg } private fun KotlinResolutionCandidate.prepareExpectedType(expectedType: UnwrappedType): UnwrappedType { - val resultType = knownTypeParametersResultingSubstitutor?.substitute(expectedType) ?: expectedType - return resolvedCall.freshVariablesSubstitutor.safeSubstitute(resultType) + val resultType = resolvedCall.freshVariablesSubstitutor.safeSubstitute(expectedType) + return resolvedCall.knownParametersSubstitutor.safeSubstitute(resultType) } internal object CheckReceivers : ResolutionPart() { @@ -714,7 +743,7 @@ internal object ErrorDescriptorResolutionPart : ResolutionPart() { resolvedCall.typeArgumentMappingByOriginal = TypeArgumentsToParametersMapper.TypeArgumentsMapping.NoExplicitArguments resolvedCall.argumentMappingByOriginal = emptyMap() resolvedCall.freshVariablesSubstitutor = FreshVariableNewTypeSubstitutor.Empty - resolvedCall.knownParametersSubstitutor = TypeSubstitutor.EMPTY + resolvedCall.knownParametersSubstitutor = EmptySubstitutor resolvedCall.argumentToCandidateParameter = emptyMap() kotlinCall.explicitReceiver?.safeAs()?.let { 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 4bb9ca05567..f637d19717a 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 @@ -15,7 +15,7 @@ import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor import org.jetbrains.kotlin.types.checker.intersectTypes import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker -interface NewTypeSubstitutor: TypeSubstitutorMarker { +interface NewTypeSubstitutor : TypeSubstitutorMarker { fun substituteNotNullTypeWithConstructor(constructor: TypeConstructor): UnwrappedType? fun safeSubstitute(type: UnwrappedType): UnwrappedType = @@ -23,6 +23,15 @@ interface NewTypeSubstitutor: TypeSubstitutorMarker { val isEmpty: Boolean + /** + * Returns not null when substitutor manages specific type projection substitution by itself. + * Intended for corner cases involving interactions with legacy type substitutor, + * please consider using substituteNotNullTypeWithConstructor instead of making manual projection substitutions. + */ + fun substituteArgumentProjection(argument: TypeProjection): TypeProjection? { + return null + } + private fun substitute(type: UnwrappedType, keepAnnotation: Boolean, runCapturedChecks: Boolean): UnwrappedType? = when (type) { is SimpleType -> substitute(type, keepAnnotation, runCapturedChecks) @@ -165,6 +174,13 @@ interface NewTypeSubstitutor: TypeSubstitutorMarker { val argument = arguments[index] if (argument.isStarProjection) continue + + val specialProjectionSubstitution = substituteArgumentProjection(argument) + if (specialProjectionSubstitution != null) { + newArguments[index] = specialProjectionSubstitution + continue + } + val substitutedArgumentType = substitute(argument.type.unwrap(), keepAnnotation, runCapturedChecks) ?: continue newArguments[index] = TypeProjectionImpl(argument.projectionKind, substitutedArgumentType) @@ -205,24 +221,39 @@ class FreshVariableNewTypeSubstitutor(val freshVariables: List abstract val freshVariablesSubstitutor: FreshVariableNewTypeSubstitutor - abstract val knownParametersSubstitutor: TypeSubstitutor + abstract val knownParametersSubstitutor: NewTypeSubstitutor abstract val argumentsWithConversion: Map abstract val argumentsWithSuspendConversion: Map abstract val argumentsWithUnitConversion: Map diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt index 2fff5ea4195..1909bafffa2 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.calls.components.* import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor +import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintSystemError import org.jetbrains.kotlin.resolve.calls.inference.model.LowerPriorityToPreserveCompatibility @@ -194,7 +195,7 @@ class MutableResolvedCallAtom( override lateinit var typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping override lateinit var argumentMappingByOriginal: Map override lateinit var freshVariablesSubstitutor: FreshVariableNewTypeSubstitutor - override lateinit var knownParametersSubstitutor: TypeSubstitutor + override lateinit var knownParametersSubstitutor: NewTypeSubstitutor lateinit var argumentToCandidateParameter: Map private var samAdapterMap: HashMap? = null private var suspendAdapterMap: HashMap? = null diff --git a/compiler/testData/diagnostics/tests/generics/kt5508.fir.kt b/compiler/testData/diagnostics/tests/generics/kt5508.fir.kt index 7d0c2dfac64..c9daf5ae02c 100644 --- a/compiler/testData/diagnostics/tests/generics/kt5508.fir.kt +++ b/compiler/testData/diagnostics/tests/generics/kt5508.fir.kt @@ -1,4 +1,3 @@ -// !WITH_NEW_INFERENCE // KT-5508 Stackoverflow in type substitution abstract class A { diff --git a/compiler/testData/diagnostics/tests/generics/kt5508.kt b/compiler/testData/diagnostics/tests/generics/kt5508.kt index 4c13070bdfc..f1bbe71ad06 100644 --- a/compiler/testData/diagnostics/tests/generics/kt5508.kt +++ b/compiler/testData/diagnostics/tests/generics/kt5508.kt @@ -1,4 +1,3 @@ -// !WITH_NEW_INFERENCE // KT-5508 Stackoverflow in type substitution abstract class A { @@ -6,7 +5,7 @@ abstract class A { public abstract fun bar(x: T) public inner abstract class B : A>() { - public inner class C : B>() + public inner class C : B>() { // Here B> means A.B>.B.B.C>>.B.B>.B.B.C>.C> // while for being a correct override it should be A.B>.B.B.C> diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt41386.fir.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt41386.fir.kt new file mode 100644 index 00000000000..81e07c9dfc7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt41386.fir.kt @@ -0,0 +1,8 @@ +// !LANGUAGE: +NewInference + +open class Test(val map1 : Map, val map2 : Map) { + open val inverse: Test = object : Test(map2, map1) { + override val inverse: Test + get() = this@Test + } +} diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt41386.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt41386.kt new file mode 100644 index 00000000000..39ec46c8ec7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt41386.kt @@ -0,0 +1,8 @@ +// !LANGUAGE: +NewInference + +open class Test(val map1 : Map, val map2 : Map) { + open val inverse: Test = object : Test(map2, map1) { + override val inverse: Test + get() = this@Test + } +} diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt41386.txt b/compiler/testData/diagnostics/tests/inference/regressions/kt41386.txt new file mode 100644 index 00000000000..2906ee3eb9f --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt41386.txt @@ -0,0 +1,11 @@ +package + +public open class Test { + public constructor Test(/*0*/ map1: kotlin.collections.Map, /*1*/ map2: kotlin.collections.Map) + public open val inverse: Test + public final val map1: kotlin.collections.Map + public final val map2: kotlin.collections.Map + 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/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 1542c3b5490..123e845722f 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -11944,6 +11944,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali runTest("compiler/testData/diagnostics/tests/inference/regressions/kt38691.kt"); } + @TestMetadata("kt41386.kt") + public void testKt41386() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/regressions/kt41386.kt"); + } + @TestMetadata("kt4420.kt") public void testKt4420() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/regressions/kt4420.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 282110adefc..f4d086bd377 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -11939,6 +11939,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/inference/regressions/kt38691.kt"); } + @TestMetadata("kt41386.kt") + public void testKt41386() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/regressions/kt41386.kt"); + } + @TestMetadata("kt4420.kt") public void testKt4420() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/regressions/kt4420.kt");