[NI] Use new type substitutor for known type parameters
Use known type parameters substitutor after substitutor for fresh variables. The old logic of substituions had the following order: - replace known type parameters - replace type parameters with type variables - complete inference - replace type variables with inferred types According to the updated logic, replacement goes as follows: - replace type parameters with type variables - replace known type parameters; if they were variables, this will effectively remove them from inference - complete inference - replace remaining type variables with inferred types Support projection substitution in new type substitutor. It is needed for correct interaction with old type substitutor. Old type substitutors can contain mappings constructor -> projection which couldn't be expressed correctly with existing substitutor API in some cases. ^KT-41386 Fixed
This commit is contained in:
+5
@@ -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");
|
||||
|
||||
+3
-4
@@ -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<D : CallableDescriptor>(
|
||||
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? {
|
||||
|
||||
+37
-8
@@ -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<TypeConstructor, UnwrappedType>().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<SimpleKotlinCallArgument>()?.let {
|
||||
|
||||
+43
-12
@@ -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<TypeVariableFromC
|
||||
}
|
||||
}
|
||||
|
||||
fun createCompositeSubstitutor(appliedFirst: NewTypeSubstitutor, appliedLast: TypeSubstitutor): NewTypeSubstitutor {
|
||||
if (appliedLast.isEmpty) return appliedFirst
|
||||
fun createCompositeSubstitutor(appliedFirst: TypeSubstitutor, appliedLast: NewTypeSubstitutor): NewTypeSubstitutor {
|
||||
if (appliedFirst.isEmpty) return appliedLast
|
||||
|
||||
return object : NewTypeSubstitutor {
|
||||
override fun substituteNotNullTypeWithConstructor(constructor: TypeConstructor): UnwrappedType? {
|
||||
val substitutedOnce = appliedFirst.substituteNotNullTypeWithConstructor(constructor)
|
||||
override fun substituteArgumentProjection(argument: TypeProjection): TypeProjection? {
|
||||
val substitutedProjection = appliedFirst.substitute(argument)
|
||||
|
||||
return if (substitutedOnce != null) {
|
||||
appliedLast.substitute(substitutedOnce.unwrap())
|
||||
if (substitutedProjection == null || substitutedProjection === argument) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (substitutedProjection.isStarProjection)
|
||||
return substitutedProjection
|
||||
|
||||
val resultingType = appliedLast.safeSubstitute(substitutedProjection.type.unwrap())
|
||||
return TypeProjectionImpl(substitutedProjection.projectionKind, resultingType)
|
||||
}
|
||||
|
||||
override fun substituteNotNullTypeWithConstructor(constructor: TypeConstructor): UnwrappedType? {
|
||||
val substitutedOnce = constructor.declarationDescriptor?.defaultType?.let {
|
||||
appliedFirst.substitute(it)
|
||||
}
|
||||
|
||||
return if (substitutedOnce == null) {
|
||||
appliedLast.substituteNotNullTypeWithConstructor(constructor)
|
||||
} else {
|
||||
constructor.declarationDescriptor?.defaultType?.let {
|
||||
appliedLast.substitute(it)
|
||||
}
|
||||
appliedLast.safeSubstitute(substitutedOnce)
|
||||
}
|
||||
}
|
||||
|
||||
override val isEmpty: Boolean get() = appliedFirst.isEmpty && appliedLast.isEmpty
|
||||
override val isEmpty: Boolean
|
||||
get() = appliedFirst.isEmpty && appliedLast.isEmpty
|
||||
}
|
||||
}
|
||||
|
||||
fun NewTypeSubstitutor.composeWith(appliedAfter: TypeSubstitutor) = createCompositeSubstitutor(this, appliedAfter)
|
||||
fun TypeSubstitutor.composeWith(appliedAfter: NewTypeSubstitutor) = createCompositeSubstitutor(this, appliedAfter)
|
||||
|
||||
@@ -65,7 +65,7 @@ abstract class ResolvedCallAtom : ResolvedAtom() {
|
||||
abstract val typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping
|
||||
abstract val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
|
||||
abstract val freshVariablesSubstitutor: FreshVariableNewTypeSubstitutor
|
||||
abstract val knownParametersSubstitutor: TypeSubstitutor
|
||||
abstract val knownParametersSubstitutor: NewTypeSubstitutor
|
||||
abstract val argumentsWithConversion: Map<KotlinCallArgument, SamConversionDescription>
|
||||
abstract val argumentsWithSuspendConversion: Map<KotlinCallArgument, UnwrappedType>
|
||||
abstract val argumentsWithUnitConversion: Map<KotlinCallArgument, UnwrappedType>
|
||||
|
||||
+2
-1
@@ -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<ValueParameterDescriptor, ResolvedCallArgument>
|
||||
override lateinit var freshVariablesSubstitutor: FreshVariableNewTypeSubstitutor
|
||||
override lateinit var knownParametersSubstitutor: TypeSubstitutor
|
||||
override lateinit var knownParametersSubstitutor: NewTypeSubstitutor
|
||||
lateinit var argumentToCandidateParameter: Map<KotlinCallArgument, ValueParameterDescriptor>
|
||||
private var samAdapterMap: HashMap<KotlinCallArgument, SamConversionDescription>? = null
|
||||
private var suspendAdapterMap: HashMap<KotlinCallArgument, UnwrappedType>? = null
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// !WITH_NEW_INFERENCE
|
||||
// KT-5508 Stackoverflow in type substitution
|
||||
|
||||
abstract class A<T> {
|
||||
|
||||
+1
-2
@@ -1,4 +1,3 @@
|
||||
// !WITH_NEW_INFERENCE
|
||||
// KT-5508 Stackoverflow in type substitution
|
||||
|
||||
abstract class A<T> {
|
||||
@@ -6,7 +5,7 @@ abstract class A<T> {
|
||||
public abstract fun bar(x: T)
|
||||
|
||||
public inner abstract class B<S> : A<B<S>>() {
|
||||
public inner <!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class C<!><U> : <!NI;DEBUG_INFO_UNRESOLVED_WITH_TARGET, NI;UNRESOLVED_REFERENCE_WRONG_RECEIVER!>B<!><C<U>>()
|
||||
public inner <!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class C<!><U> : B<C<U>>()
|
||||
{
|
||||
// Here B<C<U>> means A<A<A<T>.B<S>>.B<A<T>.B<S>.C<U>>>.B<A<A<T>.B<S>>.B<A<T>.B<S>.C<U>>.C<U>>
|
||||
// while for being a correct override it should be A<A<T>.B<S>>.B<A<T>.B<S>.C<U>>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
|
||||
open class Test<T1, T2>(val map1 : Map<T1, T2>, val map2 : Map<T2, T1>) {
|
||||
open val inverse: Test<T2, T1> = object : <!INAPPLICABLE_CANDIDATE!>Test<T2, T1><!>(map2, map1) {
|
||||
override val inverse: Test<T1, T2>
|
||||
get() = this@Test
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
|
||||
open class Test<T1, T2>(val map1 : Map<T1, T2>, val map2 : Map<T2, T1>) {
|
||||
open val inverse: Test<T2, T1> = object : Test<T2, T1>(map2, map1) {
|
||||
override val inverse: Test<T1, T2>
|
||||
get() = this@Test
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package
|
||||
|
||||
public open class Test</*0*/ T1, /*1*/ T2> {
|
||||
public constructor Test</*0*/ T1, /*1*/ T2>(/*0*/ map1: kotlin.collections.Map<T1, T2>, /*1*/ map2: kotlin.collections.Map<T2, T1>)
|
||||
public open val inverse: Test<T2, T1>
|
||||
public final val map1: kotlin.collections.Map<T1, T2>
|
||||
public final val map2: kotlin.collections.Map<T2, T1>
|
||||
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
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
Generated
+5
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user