[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:
+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
|
||||
|
||||
Reference in New Issue
Block a user