Extract FE 1.0 related parts from NewConstraintSystem
This commit is contained in:
+9
-35
@@ -16,19 +16,13 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.calls.inference
|
package org.jetbrains.kotlin.resolve.calls.inference
|
||||||
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintPosition
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintPosition
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.CallableReferenceKotlinCallArgument
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.LHSResult
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.SubKotlinCallArgument
|
|
||||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||||
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||||
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
|
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
|
||||||
import org.jetbrains.kotlin.types.model.TypeVariableMarker
|
import org.jetbrains.kotlin.types.model.TypeVariableMarker
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
|
||||||
|
|
||||||
interface ConstraintSystemOperation {
|
interface ConstraintSystemOperation {
|
||||||
val hasContradiction: Boolean
|
val hasContradiction: Boolean
|
||||||
@@ -50,7 +44,6 @@ interface ConstraintSystemOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface ConstraintSystemBuilder : ConstraintSystemOperation {
|
interface ConstraintSystemBuilder : ConstraintSystemOperation {
|
||||||
//val builtIns: KotlinBuiltIns
|
|
||||||
// if runOperations return true, then this operation will be applied, and function return true
|
// if runOperations return true, then this operation will be applied, and function return true
|
||||||
fun runTransaction(runOperations: ConstraintSystemOperation.() -> Boolean): Boolean
|
fun runTransaction(runOperations: ConstraintSystemOperation.() -> Boolean): Boolean
|
||||||
|
|
||||||
@@ -63,45 +56,26 @@ fun ConstraintSystemBuilder.addSubtypeConstraintIfCompatible(
|
|||||||
lowerType: KotlinTypeMarker,
|
lowerType: KotlinTypeMarker,
|
||||||
upperType: KotlinTypeMarker,
|
upperType: KotlinTypeMarker,
|
||||||
position: ConstraintPosition
|
position: ConstraintPosition
|
||||||
): Boolean =
|
): Boolean = addConstraintIfCompatible(lowerType, upperType, position, ConstraintKind.LOWER)
|
||||||
addConstraintIfCompatible(lowerType, upperType, position, ConstraintKind.LOWER)
|
|
||||||
|
|
||||||
fun ConstraintSystemBuilder.addEqualityConstraintIfCompatible(
|
fun ConstraintSystemBuilder.addEqualityConstraintIfCompatible(
|
||||||
lowerType: KotlinTypeMarker,
|
lowerType: KotlinTypeMarker,
|
||||||
upperType: KotlinTypeMarker,
|
upperType: KotlinTypeMarker,
|
||||||
position: ConstraintPosition
|
position: ConstraintPosition
|
||||||
): Boolean =
|
): Boolean = addConstraintIfCompatible(lowerType, upperType, position, ConstraintKind.EQUALITY)
|
||||||
addConstraintIfCompatible(lowerType, upperType, position, ConstraintKind.EQUALITY)
|
|
||||||
|
|
||||||
private fun ConstraintSystemBuilder.addConstraintIfCompatible(
|
private fun ConstraintSystemBuilder.addConstraintIfCompatible(
|
||||||
lowerType: KotlinTypeMarker,
|
lowerType: KotlinTypeMarker,
|
||||||
upperType: KotlinTypeMarker,
|
upperType: KotlinTypeMarker,
|
||||||
position: ConstraintPosition,
|
position: ConstraintPosition,
|
||||||
kind: ConstraintKind
|
kind: ConstraintKind
|
||||||
) =
|
): Boolean = runTransaction {
|
||||||
runTransaction {
|
if (!hasContradiction) {
|
||||||
if (!hasContradiction) {
|
when (kind) {
|
||||||
when (kind) {
|
ConstraintKind.LOWER -> addSubtypeConstraint(lowerType, upperType, position)
|
||||||
ConstraintKind.LOWER -> addSubtypeConstraint(lowerType, upperType, position)
|
ConstraintKind.UPPER -> addSubtypeConstraint(upperType, lowerType, position)
|
||||||
ConstraintKind.UPPER -> addSubtypeConstraint(upperType, lowerType, position)
|
ConstraintKind.EQUALITY -> addEqualityConstraint(lowerType, upperType, position)
|
||||||
ConstraintKind.EQUALITY -> addEqualityConstraint(lowerType, upperType, position)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
!hasContradiction
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun PostponedArgumentsAnalyzer.Context.addSubsystemFromArgument(argument: KotlinCallArgument?): Boolean {
|
|
||||||
return when (argument) {
|
|
||||||
is SubKotlinCallArgument -> {
|
|
||||||
addOtherSystem(argument.callResult.constraintSystem)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
is CallableReferenceKotlinCallArgument -> {
|
|
||||||
addSubsystemFromArgument(argument.lhsResult.safeAs<LHSResult.Expression>()?.lshCallArgument)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> false
|
|
||||||
}
|
}
|
||||||
|
!hasContradiction
|
||||||
}
|
}
|
||||||
|
|||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* 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.resolve.calls.inference
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.CallableReferenceKotlinCallArgument
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.LHSResult
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.SubKotlinCallArgument
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||||
|
import org.jetbrains.kotlin.types.*
|
||||||
|
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
|
fun ConstraintStorage.buildResultingSubstitutor(
|
||||||
|
context: TypeSystemInferenceExtensionContext,
|
||||||
|
transformTypeVariablesToErrorTypes: Boolean = true
|
||||||
|
): NewTypeSubstitutor {
|
||||||
|
return buildAbstractResultingSubstitutor(context, transformTypeVariablesToErrorTypes) as NewTypeSubstitutor
|
||||||
|
}
|
||||||
|
|
||||||
|
val CallableDescriptor.returnTypeOrNothing: UnwrappedType
|
||||||
|
get() {
|
||||||
|
returnType?.let { return it.unwrap() }
|
||||||
|
|
||||||
|
return builtIns.nothingType
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun CallableDescriptor.substituteAndApproximateTypes(
|
||||||
|
substitutor: NewTypeSubstitutor,
|
||||||
|
typeApproximator: TypeApproximator?
|
||||||
|
): CallableDescriptor {
|
||||||
|
val wrappedSubstitution = object : TypeSubstitution() {
|
||||||
|
override fun get(key: KotlinType): TypeProjection? = null
|
||||||
|
|
||||||
|
override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance) =
|
||||||
|
substitutor.safeSubstitute(topLevelType.unwrap()).let { substitutedType ->
|
||||||
|
typeApproximator?.approximateToSuperType(
|
||||||
|
substitutedType,
|
||||||
|
TypeApproximatorConfiguration.FinalApproximationAfterResolutionAndInference
|
||||||
|
) ?: substitutedType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return substitute(TypeSubstitutor.create(wrappedSubstitution)) ?: this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun PostponedArgumentsAnalyzer.Context.addSubsystemFromArgument(argument: KotlinCallArgument?): Boolean {
|
||||||
|
return when (argument) {
|
||||||
|
is SubKotlinCallArgument -> {
|
||||||
|
addOtherSystem(argument.callResult.constraintSystem)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
is CallableReferenceKotlinCallArgument -> {
|
||||||
|
addSubsystemFromArgument(argument.lhsResult.safeAs<LHSResult.Expression>()?.lshCallArgument)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
+25
-66
@@ -16,11 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.calls.inference
|
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.model.ConstraintStorage
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
|
||||||
import org.jetbrains.kotlin.types.*
|
|
||||||
import org.jetbrains.kotlin.types.model.*
|
import org.jetbrains.kotlin.types.model.*
|
||||||
|
|
||||||
fun ConstraintStorage.buildCurrentSubstitutor(
|
fun ConstraintStorage.buildCurrentSubstitutor(
|
||||||
@@ -30,71 +26,34 @@ fun ConstraintStorage.buildCurrentSubstitutor(
|
|||||||
return context.typeSubstitutorByTypeConstructor(fixedTypeVariables.entries.associate { it.key to it.value } + additionalBindings)
|
return context.typeSubstitutorByTypeConstructor(fixedTypeVariables.entries.associate { it.key to it.value } + additionalBindings)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ConstraintStorage.buildAbstractResultingSubstitutor(context: TypeSystemInferenceExtensionContext, transformTypeVariablesToErrorTypes: Boolean = true): TypeSubstitutorMarker =
|
fun ConstraintStorage.buildAbstractResultingSubstitutor(
|
||||||
with(context) {
|
context: TypeSystemInferenceExtensionContext,
|
||||||
if (allTypeVariables.isEmpty()) return createEmptySubstitutor()
|
transformTypeVariablesToErrorTypes: Boolean = true
|
||||||
|
): TypeSubstitutorMarker = with(context) {
|
||||||
|
if (allTypeVariables.isEmpty()) return createEmptySubstitutor()
|
||||||
|
|
||||||
val currentSubstitutorMap = fixedTypeVariables.entries.associate {
|
val currentSubstitutorMap = fixedTypeVariables.entries.associate {
|
||||||
it.key to it.value
|
it.key to it.value
|
||||||
}
|
|
||||||
val uninferredSubstitutorMap = if (transformTypeVariablesToErrorTypes) {
|
|
||||||
notFixedTypeVariables.entries.associate { (freshTypeConstructor, typeVariable) ->
|
|
||||||
freshTypeConstructor to context.createErrorTypeWithCustomConstructor(
|
|
||||||
"Uninferred type",
|
|
||||||
(typeVariable.typeVariable).freshTypeConstructor()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
notFixedTypeVariables.entries.associate { (freshTypeConstructor, typeVariable) ->
|
|
||||||
freshTypeConstructor to typeVariable.typeVariable.defaultType(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return context.typeSubstitutorByTypeConstructor(currentSubstitutorMap + uninferredSubstitutorMap)
|
|
||||||
}
|
}
|
||||||
|
val uninferredSubstitutorMap = if (transformTypeVariablesToErrorTypes) {
|
||||||
|
notFixedTypeVariables.entries.associate { (freshTypeConstructor, typeVariable) ->
|
||||||
|
freshTypeConstructor to context.createErrorTypeWithCustomConstructor(
|
||||||
|
"Uninferred type",
|
||||||
|
(typeVariable.typeVariable).freshTypeConstructor()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
notFixedTypeVariables.entries.associate { (freshTypeConstructor, typeVariable) ->
|
||||||
|
freshTypeConstructor to typeVariable.typeVariable.defaultType(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return context.typeSubstitutorByTypeConstructor(currentSubstitutorMap + uninferredSubstitutorMap)
|
||||||
|
}
|
||||||
|
|
||||||
fun ConstraintStorage.buildNotFixedVariablesToNonSubtypableTypesSubstitutor(context: TypeSystemInferenceExtensionContext) =
|
fun ConstraintStorage.buildNotFixedVariablesToNonSubtypableTypesSubstitutor(
|
||||||
context.typeSubstitutorByTypeConstructor(
|
context: TypeSystemInferenceExtensionContext
|
||||||
|
): TypeSubstitutorMarker {
|
||||||
|
return context.typeSubstitutorByTypeConstructor(
|
||||||
notFixedTypeVariables.mapValues { context.createStubType(it.value.typeVariable) }
|
notFixedTypeVariables.mapValues { context.createStubType(it.value.typeVariable) }
|
||||||
)
|
)
|
||||||
|
|
||||||
fun ConstraintStorage.buildResultingSubstitutor(context: TypeSystemInferenceExtensionContext, transformTypeVariablesToErrorTypes: Boolean = true): NewTypeSubstitutor {
|
|
||||||
return buildAbstractResultingSubstitutor(context, transformTypeVariablesToErrorTypes) as NewTypeSubstitutor
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val CallableDescriptor.returnTypeOrNothing: UnwrappedType
|
|
||||||
get() {
|
|
||||||
returnType?.let { return it.unwrap() }
|
|
||||||
|
|
||||||
return builtIns.nothingType
|
|
||||||
}
|
|
||||||
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun CallableDescriptor.substituteAndApproximateTypes(
|
|
||||||
substitutor: NewTypeSubstitutor,
|
|
||||||
typeApproximator: TypeApproximator?
|
|
||||||
): CallableDescriptor {
|
|
||||||
val wrappedSubstitution = object : TypeSubstitution() {
|
|
||||||
override fun get(key: KotlinType): TypeProjection? = null
|
|
||||||
|
|
||||||
override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance) =
|
|
||||||
substitutor.safeSubstitute(topLevelType.unwrap()).let { substitutedType ->
|
|
||||||
typeApproximator?.approximateToSuperType(
|
|
||||||
substitutedType,
|
|
||||||
TypeApproximatorConfiguration.FinalApproximationAfterResolutionAndInference
|
|
||||||
) ?: substitutedType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return substitute(TypeSubstitutor.create(wrappedSubstitution)) ?: this
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun <E> MutableList<E>.trimToSize(newSize: Int) = subList(newSize, size).clear()
|
|
||||||
|
|||||||
+1
-4
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.calls.inference
|
package org.jetbrains.kotlin.resolve.calls.inference
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
|
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
|
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.components.PostponedArgumentInputTypesResolver
|
import org.jetbrains.kotlin.resolve.calls.inference.components.PostponedArgumentInputTypesResolver
|
||||||
@@ -25,7 +23,6 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
|||||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||||
|
|
||||||
interface NewConstraintSystem {
|
interface NewConstraintSystem {
|
||||||
// val builtIns: KotlinBuiltIns
|
|
||||||
val hasContradiction: Boolean
|
val hasContradiction: Boolean
|
||||||
val diagnostics: List<KotlinCallDiagnostic>
|
val diagnostics: List<KotlinCallDiagnostic>
|
||||||
|
|
||||||
@@ -37,4 +34,4 @@ interface NewConstraintSystem {
|
|||||||
fun asConstraintSystemCompleterContext(): KotlinConstraintSystemCompleter.Context
|
fun asConstraintSystemCompleterContext(): KotlinConstraintSystemCompleter.Context
|
||||||
fun asPostponedArgumentsAnalyzerContext(): PostponedArgumentsAnalyzer.Context
|
fun asPostponedArgumentsAnalyzerContext(): PostponedArgumentsAnalyzer.Context
|
||||||
fun asPostponedArgumentInputTypesResolverContext(): PostponedArgumentInputTypesResolver.Context
|
fun asPostponedArgumentInputTypesResolverContext(): PostponedArgumentInputTypesResolver.Context
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.calls.inference.model
|
package org.jetbrains.kotlin.resolve.calls.inference.model
|
||||||
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.trimToSize
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||||
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||||
import org.jetbrains.kotlin.types.*
|
import org.jetbrains.kotlin.types.*
|
||||||
@@ -14,6 +13,7 @@ import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
|||||||
import org.jetbrains.kotlin.types.model.TypeVariableMarker
|
import org.jetbrains.kotlin.types.model.TypeVariableMarker
|
||||||
import org.jetbrains.kotlin.types.typeUtil.unCapture
|
import org.jetbrains.kotlin.types.typeUtil.unCapture
|
||||||
import org.jetbrains.kotlin.utils.SmartList
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.trimToSize
|
||||||
|
|
||||||
|
|
||||||
class MutableVariableWithConstraints private constructor(
|
class MutableVariableWithConstraints private constructor(
|
||||||
|
|||||||
+1
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.types.model.*
|
|||||||
import org.jetbrains.kotlin.utils.SmartList
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
import org.jetbrains.kotlin.utils.SmartSet
|
import org.jetbrains.kotlin.utils.SmartSet
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.trimToSize
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
class NewConstraintSystemImpl(
|
class NewConstraintSystemImpl(
|
||||||
|
|||||||
@@ -172,4 +172,8 @@ inline fun <T, R> Collection<T>.foldMap(transform: (T) -> R, operation: (R, R) -
|
|||||||
result = operation(result, transform(iterator.next()))
|
result = operation(result, transform(iterator.next()))
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <E> MutableList<E>.trimToSize(newSize: Int) {
|
||||||
|
subList(newSize, size).clear()
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user