[NI] Implement NewTypeSubstitutor

This commit is contained in:
Stanislav Erokhin
2017-04-12 15:23:36 +03:00
parent ff8a57dc26
commit 0c79949cf1
6 changed files with 159 additions and 30 deletions
@@ -21,19 +21,19 @@ import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
import org.jetbrains.kotlin.resolve.calls.inference.components.FixationOrderCalculator
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver
import org.jetbrains.kotlin.resolve.calls.inference.model.ExpectedTypeConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaTypeVariable
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.resolve.calls.inference.model.NotEnoughInformationForTypeParameter
import org.jetbrains.kotlin.resolve.calls.inference.returnTypeOrNothing
import org.jetbrains.kotlin.resolve.calls.inference.substitute
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateStatus
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addIfNotNull
@@ -45,8 +45,8 @@ class KotlinCallCompleter(
interface Context {
val innerCalls: List<ResolvedKotlinCall.OnlyResolvedKotlinCall>
val hasContradiction: Boolean
fun buildCurrentSubstitutor(): TypeSubstitutor
fun buildResultingSubstitutor(): TypeSubstitutor
fun buildCurrentSubstitutor(): NewTypeSubstitutor
fun buildResultingSubstitutor(): NewTypeSubstitutor
val lambdaArguments: List<ResolvedLambdaArgument>
// type can be proper if it not contains not fixed type variables
@@ -100,7 +100,7 @@ class KotlinCallCompleter(
return ResolvedKotlinCall.CompletedResolvedKotlinCall(completedCall, competedCalls)
}
private fun KotlinResolutionCandidate.toCompletedCall(substitutor: TypeSubstitutor): CompletedKotlinCall {
private fun KotlinResolutionCandidate.toCompletedCall(substitutor: NewTypeSubstitutor): CompletedKotlinCall {
if (this is VariableAsFunctionKotlinResolutionCandidate) {
val variable = resolvedVariable.toCompletedCall(substitutor)
val invoke = invokeCandidate.toCompletedCall(substitutor)
@@ -110,10 +110,10 @@ class KotlinCallCompleter(
return (this as SimpleKotlinResolutionCandidate).toCompletedCall(substitutor)
}
private fun SimpleKotlinResolutionCandidate.toCompletedCall(substitutor: TypeSubstitutor): CompletedKotlinCall.Simple {
private fun SimpleKotlinResolutionCandidate.toCompletedCall(substitutor: NewTypeSubstitutor): CompletedKotlinCall.Simple {
val resultingDescriptor = if (descriptorWithFreshTypes.typeParameters.isNotEmpty()) descriptorWithFreshTypes.substitute(substitutor)!! else descriptorWithFreshTypes
val typeArguments = descriptorWithFreshTypes.typeParameters.map { substitutor.safeSubstitute(it.defaultType, Variance.INVARIANT).unwrap() }
val typeArguments = descriptorWithFreshTypes.typeParameters.map { substitutor.safeSubstitute(it.defaultType) }
val status = computeStatus(this, resultingDescriptor)
return CompletedKotlinCall.Simple(kotlinCall, candidateDescriptor, resultingDescriptor, status, explicitReceiverKind,
@@ -226,7 +226,7 @@ class KotlinCallCompleter(
private fun analyzeLambda(c: Context, lambdaAnalyzer: LambdaAnalyzer, topLevelCallContext: KotlinCallContext, topLevelCall: KotlinCall, lambda: ResolvedLambdaArgument) {
val currentSubstitutor = c.buildCurrentSubstitutor()
fun substitute(type: UnwrappedType) = currentSubstitutor.safeSubstitute(type, Variance.INVARIANT).unwrap()
fun substitute(type: UnwrappedType) = currentSubstitutor.safeSubstitute(type)
val receiver = lambda.receiver?.let(::substitute)
val parameters = lambda.parameters.map(::substitute)
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMa
import org.jetbrains.kotlin.resolve.calls.inference.model.DeclaredUpperBoundConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.model.ExplicitTypeParameterConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableFromCallableDescriptor
import org.jetbrains.kotlin.resolve.calls.inference.substitute
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.smartcasts.getReceiverValueWithSmartCast
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.*
@@ -164,7 +165,7 @@ internal object CreteDescriptorWithFreshTypeVariables : ResolutionPart {
*/
val toFixedTypeParameters = csBuilder.simplify()
// todo optimize -- composite substitutions before run safeSubstitute
descriptorWithFreshTypes = candidateDescriptor.safeSubstitute(toFreshVariables).safeSubstitute(toFixedTypeParameters)
descriptorWithFreshTypes = candidateDescriptor.substitute(toFreshVariables)!!.substitute(toFixedTypeParameters)!!
return emptyList()
}
@@ -16,11 +16,11 @@
package org.jetbrains.kotlin.resolve.calls.inference
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.UnwrappedType
@@ -43,5 +43,5 @@ interface ConstraintSystemBuilder {
* This function removes variables for which we know exact type.
* @return substitutor from typeVariable to result
*/
fun simplify(): TypeSubstitutor
fun simplify(): NewTypeSubstitutor
}
@@ -17,17 +17,15 @@
package org.jetbrains.kotlin.resolve.calls.inference
import org.jetbrains.kotlin.descriptors.CallableDescriptor
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.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.TypeConstructorSubstitution
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
import org.jetbrains.kotlin.types.*
fun ConstraintStorage.buildCurrentSubstitutor() = TypeConstructorSubstitution.createByConstructorsMap(fixedTypeVariables.entries.associate {
it.key to it.value.asTypeProjection()
}).buildSubstitutor()
fun ConstraintStorage.buildCurrentSubstitutor() = NewTypeSubstitutorByConstructorMap(fixedTypeVariables.entries.associate {
it.key to it.value
})
val CallableDescriptor.returnTypeOrNothing: UnwrappedType
get() {
@@ -38,3 +36,11 @@ val CallableDescriptor.returnTypeOrNothing: UnwrappedType
fun TypeSubstitutor.substitute(type: UnwrappedType): UnwrappedType = safeSubstitute(type, Variance.INVARIANT).unwrap()
fun CallableDescriptor.substitute(substitutor: NewTypeSubstitutor): CallableDescriptor? {
val wrappedSubstitution = object : TypeSubstitution() {
override fun get(key: KotlinType): TypeProjection? = null
override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance) = substitutor.safeSubstitute(topLevelType.unwrap())
}
return substitute(TypeSubstitutor.create(wrappedSubstitution))
}
@@ -0,0 +1,123 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve.calls.inference.components
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.NewCapturedType
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor
import org.jetbrains.kotlin.types.checker.intersectTypes
interface NewTypeSubstitutor {
fun substituteNotNullTypeWithConstructor(constructor: TypeConstructor): UnwrappedType?
val isEmpty: Boolean
fun safeSubstitute(type: UnwrappedType): UnwrappedType = substitute(type) ?: type
// null means that this type isn't changed
fun substitute(type: UnwrappedType): UnwrappedType? =
when (type) {
is SimpleType -> substitute(type)
is FlexibleType -> if (type is DynamicType || type is RawType) {
null
}
else {
val lowerBound = substitute(type.lowerBound)
val upperBound = substitute(type.upperBound)
if (lowerBound == null && upperBound == null) {
null
}
else {
// todo discuss lowerIfFlexible and upperIfFlexible
FlexibleTypeImpl(lowerBound?.lowerIfFlexible() ?: type.lowerBound, upperBound?.upperIfFlexible() ?: type.upperBound)
}
}
}
fun substitute(type: SimpleType): UnwrappedType? {
if (type.isError) return null
if (type.arguments.isNotEmpty()) {
return substituteParametrizedType(type)
}
val typeConstructor = type.constructor
if (typeConstructor is NewCapturedTypeConstructor) {
assert(type is NewCapturedType) { // KT-16147
"Type is inconsistent -- somewhere we create type with typeConstructor = $typeConstructor " +
"and class: ${type::class.java.canonicalName}. type.toString() = $type"
}
val lower = (type as NewCapturedType).lowerType?.let { substitute(it) }
if (lower != null) throw IllegalStateException("Illegal type substitutor: $this, " +
"because for captured type '$type' lower type approximation should be null, but it is: '$lower'," +
"original lower type: '${type.lowerType}")
type.constructor.supertypes.forEach { supertype ->
substitute(supertype)?.let {
throw IllegalStateException("Illegal type substitutor: $this, " +
"because for captured type '$type' supertype approximation should be null, but it is: '$supertype'," +
"original supertype: '$supertype'")
}
}
return null
}
if (typeConstructor is IntersectionTypeConstructor) {
var thereIsChanges = false
val newTypes = typeConstructor.supertypes.map {
substitute(it.unwrap())?.apply { thereIsChanges = true } ?: it.unwrap()
}
if (!thereIsChanges) return null
return intersectTypes(newTypes).let { if (type.isMarkedNullable) it.makeNullableAsSpecified(true) else it }
}
// simple classifier type
val replacement = substituteNotNullTypeWithConstructor(typeConstructor) ?: return null
return if (type.isMarkedNullable) replacement.makeNullableAsSpecified(true) else replacement
}
private fun substituteParametrizedType(type: SimpleType): UnwrappedType? {
val parameters = type.constructor.parameters
val arguments = type.arguments
if (parameters.size != arguments.size) {
// todo error type or exception?
return ErrorUtils.createErrorType("Inconsistent type: $type (parameters.size = ${parameters.size}, arguments.size = ${arguments.size})")
}
val newArguments = arrayOfNulls<TypeProjection?>(arguments.size)
for (index in arguments.indices) {
val argument = arguments[index]
if (argument.isStarProjection) continue
val substitutedArgumentType = substitute(argument.type.unwrap()) ?: continue
newArguments[index] = TypeProjectionImpl(argument.projectionKind, substitutedArgumentType)
}
if (newArguments.all { it == null }) return null
val newArgumentsList = arguments.mapIndexed { index, oldArgument -> newArguments[index] ?: oldArgument }
return type.replace(newArgumentsList)
}
}
class NewTypeSubstitutorByConstructorMap(val map: Map<TypeConstructor, UnwrappedType>) : NewTypeSubstitutor {
override val isEmpty get() = map.isEmpty()
override fun substituteNotNullTypeWithConstructor(constructor: TypeConstructor): UnwrappedType? = map[constructor]
}
@@ -20,15 +20,14 @@ import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.buildCurrentSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
import org.jetbrains.kotlin.resolve.calls.inference.components.FixationOrderCalculator
import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver
import org.jetbrains.kotlin.resolve.calls.inference.components.*
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.contains
import java.util.*
@@ -125,7 +124,7 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
return fixedVariables
}
override fun simplify(): TypeSubstitutor {
override fun simplify(): NewTypeSubstitutor {
checkState(State.BUILDING)
var fixedVariables = getVariablesForFixation()
@@ -235,20 +234,20 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
return !type.contains { storage.notFixedTypeVariables.containsKey(it.constructor) }
}
override fun buildCurrentSubstitutor(): TypeSubstitutor {
override fun buildCurrentSubstitutor(): NewTypeSubstitutor {
checkState(State.COMPLETION)
return storage.buildCurrentSubstitutor()
}
override fun buildResultingSubstitutor(): TypeSubstitutor {
override fun buildResultingSubstitutor(): NewTypeSubstitutor {
checkState(State.COMPLETION)
val currentSubstitutorMap = storage.fixedTypeVariables.entries.associate {
it.key to it.value.asTypeProjection()
it.key to it.value
}
val uninferredSubstitutorMap = storage.notFixedTypeVariables.entries.associate { (freshTypeConstructor, typeVariable) ->
freshTypeConstructor to ErrorUtils.createErrorTypeWithCustomConstructor("Uninferred type", typeVariable.typeVariable.freshTypeConstructor).asTypeProjection()
freshTypeConstructor to ErrorUtils.createErrorTypeWithCustomConstructor("Uninferred type", typeVariable.typeVariable.freshTypeConstructor)
}
return TypeConstructorSubstitution.createByConstructorsMap(currentSubstitutorMap + uninferredSubstitutorMap).buildSubstitutor()
return NewTypeSubstitutorByConstructorMap(currentSubstitutorMap + uninferredSubstitutorMap)
}
}