[Misc] Move TypeAliasExpander to core
This commit is contained in:
committed by
Dmitry Savvinov
parent
7ba3f7e599
commit
c1144f35f1
@@ -1352,21 +1352,6 @@ public class DescriptorResolver {
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkBoundsInTypeAlias(
|
||||
@NotNull TypeAliasExpansionReportStrategy reportStrategy,
|
||||
@NotNull KotlinType unsubstitutedArgument,
|
||||
@NotNull KotlinType typeArgument,
|
||||
@NotNull TypeParameterDescriptor typeParameterDescriptor,
|
||||
@NotNull TypeSubstitutor substitutor
|
||||
) {
|
||||
for (KotlinType bound : typeParameterDescriptor.getUpperBounds()) {
|
||||
KotlinType substitutedBound = substitutor.safeSubstitute(bound, Variance.INVARIANT);
|
||||
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(typeArgument, substitutedBound)) {
|
||||
reportStrategy.boundsViolationInSubstitution(substitutedBound, unsubstitutedArgument, typeArgument, typeParameterDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean checkHasOuterClassInstance(
|
||||
@NotNull LexicalScope scope,
|
||||
@NotNull BindingTrace trace,
|
||||
|
||||
@@ -1,283 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.annotations.composeAnnotations
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.containsTypeAliasParameters
|
||||
import org.jetbrains.kotlin.types.typeUtil.requiresTypeAliasExpansion
|
||||
|
||||
class TypeAliasExpander(
|
||||
private val reportStrategy: TypeAliasExpansionReportStrategy,
|
||||
private val shouldCheckBounds: Boolean
|
||||
) {
|
||||
|
||||
fun expand(typeAliasExpansion: TypeAliasExpansion, annotations: Annotations) =
|
||||
expandRecursively(
|
||||
typeAliasExpansion, annotations,
|
||||
isNullable = false, recursionDepth = 0, withAbbreviatedType = true
|
||||
)
|
||||
|
||||
fun expandWithoutAbbreviation(typeAliasExpansion: TypeAliasExpansion, annotations: Annotations) =
|
||||
expandRecursively(
|
||||
typeAliasExpansion, annotations,
|
||||
isNullable = false, recursionDepth = 0, withAbbreviatedType = false
|
||||
)
|
||||
|
||||
private fun expandRecursively(
|
||||
typeAliasExpansion: TypeAliasExpansion,
|
||||
annotations: Annotations,
|
||||
isNullable: Boolean,
|
||||
recursionDepth: Int,
|
||||
withAbbreviatedType: Boolean
|
||||
): SimpleType {
|
||||
val underlyingProjection = TypeProjectionImpl(Variance.INVARIANT, typeAliasExpansion.descriptor.underlyingType)
|
||||
val expandedProjection = expandTypeProjection(underlyingProjection, typeAliasExpansion, null, recursionDepth)
|
||||
val expandedType = expandedProjection.type.asSimpleType()
|
||||
|
||||
if (expandedType.isError) return expandedType
|
||||
|
||||
assert(expandedProjection.projectionKind == Variance.INVARIANT) {
|
||||
"Type alias expansion: result for ${typeAliasExpansion.descriptor} is ${expandedProjection.projectionKind}, should be invariant"
|
||||
}
|
||||
|
||||
checkRepeatedAnnotations(expandedType.annotations, annotations)
|
||||
val expandedTypeWithExtraAnnotations =
|
||||
expandedType.combineAnnotations(annotations).let { TypeUtils.makeNullableIfNeeded(it, isNullable) }
|
||||
|
||||
return if (withAbbreviatedType)
|
||||
expandedTypeWithExtraAnnotations.withAbbreviation(typeAliasExpansion.createAbbreviation(annotations, isNullable))
|
||||
else
|
||||
expandedTypeWithExtraAnnotations
|
||||
}
|
||||
|
||||
private fun TypeAliasExpansion.createAbbreviation(annotations: Annotations, isNullable: Boolean) =
|
||||
KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
|
||||
annotations,
|
||||
descriptor.typeConstructor,
|
||||
arguments,
|
||||
isNullable,
|
||||
MemberScope.Empty
|
||||
)
|
||||
|
||||
private fun expandTypeProjection(
|
||||
underlyingProjection: TypeProjection,
|
||||
typeAliasExpansion: TypeAliasExpansion,
|
||||
typeParameterDescriptor: TypeParameterDescriptor?,
|
||||
recursionDepth: Int
|
||||
): TypeProjection {
|
||||
// TODO refactor TypeSubstitutor to introduce custom diagnostics
|
||||
assertRecursionDepth(recursionDepth, typeAliasExpansion.descriptor)
|
||||
|
||||
if (underlyingProjection.isStarProjection) return TypeUtils.makeStarProjection(typeParameterDescriptor!!)
|
||||
|
||||
val underlyingType = underlyingProjection.type
|
||||
val argument = typeAliasExpansion.getReplacement(underlyingType.constructor)
|
||||
?: return expandNonArgumentTypeProjection(
|
||||
underlyingProjection,
|
||||
typeAliasExpansion,
|
||||
recursionDepth
|
||||
)
|
||||
|
||||
if (argument.isStarProjection) return TypeUtils.makeStarProjection(typeParameterDescriptor!!)
|
||||
|
||||
val argumentType = argument.type.unwrap()
|
||||
|
||||
val resultingVariance = run {
|
||||
val argumentVariance = argument.projectionKind
|
||||
val underlyingVariance = underlyingProjection.projectionKind
|
||||
|
||||
val substitutionVariance =
|
||||
when {
|
||||
underlyingVariance == argumentVariance -> argumentVariance
|
||||
underlyingVariance == Variance.INVARIANT -> argumentVariance
|
||||
argumentVariance == Variance.INVARIANT -> underlyingVariance
|
||||
else -> {
|
||||
reportStrategy.conflictingProjection(typeAliasExpansion.descriptor, typeParameterDescriptor, argumentType)
|
||||
argumentVariance
|
||||
}
|
||||
}
|
||||
|
||||
val parameterVariance = typeParameterDescriptor?.variance ?: Variance.INVARIANT
|
||||
|
||||
when {
|
||||
parameterVariance == substitutionVariance -> substitutionVariance
|
||||
parameterVariance == Variance.INVARIANT -> substitutionVariance
|
||||
substitutionVariance == Variance.INVARIANT -> Variance.INVARIANT
|
||||
else -> {
|
||||
reportStrategy.conflictingProjection(typeAliasExpansion.descriptor, typeParameterDescriptor, argumentType)
|
||||
substitutionVariance
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkRepeatedAnnotations(underlyingType.annotations, argumentType.annotations)
|
||||
|
||||
val substitutedType =
|
||||
if (argumentType is DynamicType)
|
||||
argumentType.combineAnnotations(underlyingType.annotations)
|
||||
else
|
||||
argumentType.asSimpleType().combineNullabilityAndAnnotations(underlyingType)
|
||||
|
||||
return TypeProjectionImpl(resultingVariance, substitutedType)
|
||||
}
|
||||
|
||||
private fun DynamicType.combineAnnotations(newAnnotations: Annotations): DynamicType =
|
||||
replaceAnnotations(createCombinedAnnotations(newAnnotations))
|
||||
|
||||
private fun SimpleType.combineAnnotations(newAnnotations: Annotations): SimpleType =
|
||||
if (isError) this else replace(newAnnotations = createCombinedAnnotations(newAnnotations))
|
||||
|
||||
private fun KotlinType.createCombinedAnnotations(newAnnotations: Annotations): Annotations {
|
||||
if (isError) return annotations
|
||||
|
||||
return composeAnnotations(newAnnotations, annotations)
|
||||
}
|
||||
|
||||
private fun checkRepeatedAnnotations(existingAnnotations: Annotations, newAnnotations: Annotations) {
|
||||
val existingAnnotationFqNames = existingAnnotations.mapTo(hashSetOf()) { it.fqName }
|
||||
|
||||
for (annotation in newAnnotations) {
|
||||
if (annotation.fqName in existingAnnotationFqNames) {
|
||||
reportStrategy.repeatedAnnotation(annotation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun SimpleType.combineNullability(fromType: KotlinType) =
|
||||
TypeUtils.makeNullableIfNeeded(this, fromType.isMarkedNullable)
|
||||
|
||||
private fun SimpleType.combineNullabilityAndAnnotations(fromType: KotlinType) =
|
||||
combineNullability(fromType).combineAnnotations(fromType.annotations)
|
||||
|
||||
private fun expandNonArgumentTypeProjection(
|
||||
originalProjection: TypeProjection,
|
||||
typeAliasExpansion: TypeAliasExpansion,
|
||||
recursionDepth: Int
|
||||
): TypeProjection {
|
||||
val originalType = originalProjection.type.unwrap()
|
||||
|
||||
if (originalType.isDynamic()) return originalProjection
|
||||
|
||||
val type = originalType.asSimpleType()
|
||||
|
||||
if (type.isError || !type.requiresTypeAliasExpansion()) {
|
||||
return originalProjection
|
||||
}
|
||||
|
||||
val typeConstructor = type.constructor
|
||||
val typeDescriptor = typeConstructor.declarationDescriptor
|
||||
|
||||
assert(typeConstructor.parameters.size == type.arguments.size) { "Unexpected malformed type: $type" }
|
||||
|
||||
return when (typeDescriptor) {
|
||||
is TypeParameterDescriptor -> {
|
||||
originalProjection
|
||||
}
|
||||
is TypeAliasDescriptor -> {
|
||||
if (typeAliasExpansion.isRecursion(typeDescriptor)) {
|
||||
reportStrategy.recursiveTypeAlias(typeDescriptor)
|
||||
return TypeProjectionImpl(
|
||||
Variance.INVARIANT,
|
||||
ErrorUtils.createErrorType("Recursive type alias: ${typeDescriptor.name}")
|
||||
)
|
||||
}
|
||||
|
||||
val expandedArguments = type.arguments.mapIndexed { i, typeAliasArgument ->
|
||||
expandTypeProjection(typeAliasArgument, typeAliasExpansion, typeConstructor.parameters[i], recursionDepth + 1)
|
||||
}
|
||||
|
||||
val nestedExpansion = TypeAliasExpansion.create(typeAliasExpansion, typeDescriptor, expandedArguments)
|
||||
|
||||
val nestedExpandedType = expandRecursively(
|
||||
nestedExpansion, type.annotations,
|
||||
isNullable = type.isMarkedNullable,
|
||||
recursionDepth = recursionDepth + 1,
|
||||
withAbbreviatedType = false
|
||||
)
|
||||
|
||||
val substitutedType = type.substituteArguments(typeAliasExpansion, recursionDepth)
|
||||
|
||||
// 'dynamic' type can't be abbreviated - will be reported separately
|
||||
val typeWithAbbreviation =
|
||||
if (nestedExpandedType.isDynamic()) nestedExpandedType else nestedExpandedType.withAbbreviation(substitutedType)
|
||||
|
||||
TypeProjectionImpl(originalProjection.projectionKind, typeWithAbbreviation)
|
||||
}
|
||||
else -> {
|
||||
val substitutedType = type.substituteArguments(typeAliasExpansion, recursionDepth)
|
||||
|
||||
checkTypeArgumentsSubstitution(type, substitutedType)
|
||||
|
||||
TypeProjectionImpl(originalProjection.projectionKind, substitutedType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun SimpleType.substituteArguments(typeAliasExpansion: TypeAliasExpansion, recursionDepth: Int): SimpleType {
|
||||
val typeConstructor = this.constructor
|
||||
|
||||
val substitutedArguments = this.arguments.mapIndexed { i, originalArgument ->
|
||||
val projection = expandTypeProjection(
|
||||
originalArgument, typeAliasExpansion, typeConstructor.parameters[i], recursionDepth + 1
|
||||
)
|
||||
if (projection.isStarProjection) projection
|
||||
else TypeProjectionImpl(
|
||||
projection.projectionKind,
|
||||
TypeUtils.makeNullableIfNeeded(projection.type, originalArgument.type.isMarkedNullable)
|
||||
)
|
||||
}
|
||||
|
||||
return this.replace(newArguments = substitutedArguments)
|
||||
}
|
||||
|
||||
private fun checkTypeArgumentsSubstitution(unsubstitutedType: KotlinType, substitutedType: KotlinType) {
|
||||
val typeSubstitutor = TypeSubstitutor.create(substitutedType)
|
||||
|
||||
substitutedType.arguments.forEachIndexed { i, substitutedArgument ->
|
||||
if (!substitutedArgument.isStarProjection && !substitutedArgument.type.containsTypeAliasParameters()) {
|
||||
val unsubstitutedArgument = unsubstitutedType.arguments[i]
|
||||
val typeParameter = unsubstitutedType.constructor.parameters[i]
|
||||
if (shouldCheckBounds) {
|
||||
DescriptorResolver.checkBoundsInTypeAlias(
|
||||
reportStrategy,
|
||||
unsubstitutedArgument.type,
|
||||
substitutedArgument.type,
|
||||
typeParameter,
|
||||
typeSubstitutor
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val MAX_RECURSION_DEPTH = 100
|
||||
|
||||
private fun assertRecursionDepth(recursionDepth: Int, typeAliasDescriptor: TypeAliasDescriptor) {
|
||||
if (recursionDepth > MAX_RECURSION_DEPTH) {
|
||||
throw AssertionError("Too deep recursion while expanding type alias ${typeAliasDescriptor.name}")
|
||||
}
|
||||
}
|
||||
|
||||
val NON_REPORTING = TypeAliasExpander(TypeAliasExpansionReportStrategy.DO_NOTHING, false)
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.TypeProjection
|
||||
|
||||
class TypeAliasExpansion private constructor(
|
||||
val parent: TypeAliasExpansion?,
|
||||
val descriptor: TypeAliasDescriptor,
|
||||
val arguments: List<TypeProjection>,
|
||||
val mapping: Map<TypeParameterDescriptor, TypeProjection>
|
||||
) {
|
||||
fun getReplacement(constructor: TypeConstructor): TypeProjection? {
|
||||
val descriptor = constructor.declarationDescriptor
|
||||
return if (descriptor is TypeParameterDescriptor)
|
||||
mapping[descriptor]
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
fun isRecursion(descriptor: TypeAliasDescriptor): Boolean =
|
||||
this.descriptor == descriptor || (parent?.isRecursion(descriptor) ?: false)
|
||||
|
||||
companion object {
|
||||
fun create(
|
||||
parent: TypeAliasExpansion?,
|
||||
typeAliasDescriptor: TypeAliasDescriptor,
|
||||
arguments: List<TypeProjection>
|
||||
): TypeAliasExpansion {
|
||||
val typeParameters = typeAliasDescriptor.typeConstructor.parameters.map { it.original }
|
||||
val mappedArguments = typeParameters.zip(arguments).toMap()
|
||||
return TypeAliasExpansion(parent, typeAliasDescriptor, arguments, mappedArguments)
|
||||
}
|
||||
|
||||
fun createWithFormalArguments(typeAliasDescriptor: TypeAliasDescriptor) =
|
||||
create(null, typeAliasDescriptor, emptyList())
|
||||
}
|
||||
}
|
||||
-57
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
interface TypeAliasExpansionReportStrategy {
|
||||
fun wrongNumberOfTypeArguments(typeAlias: TypeAliasDescriptor, numberOfParameters: Int)
|
||||
fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, substitutedArgument: KotlinType)
|
||||
fun recursiveTypeAlias(typeAlias: TypeAliasDescriptor)
|
||||
fun boundsViolationInSubstitution(
|
||||
bound: KotlinType,
|
||||
unsubstitutedArgument: KotlinType,
|
||||
argument: KotlinType,
|
||||
typeParameter: TypeParameterDescriptor
|
||||
)
|
||||
|
||||
fun repeatedAnnotation(annotation: AnnotationDescriptor)
|
||||
|
||||
object DO_NOTHING : TypeAliasExpansionReportStrategy {
|
||||
override fun wrongNumberOfTypeArguments(typeAlias: TypeAliasDescriptor, numberOfParameters: Int) {}
|
||||
override fun conflictingProjection(
|
||||
typeAlias: TypeAliasDescriptor,
|
||||
typeParameter: TypeParameterDescriptor?,
|
||||
substitutedArgument: KotlinType
|
||||
) {
|
||||
}
|
||||
|
||||
override fun recursiveTypeAlias(typeAlias: TypeAliasDescriptor) {}
|
||||
override fun boundsViolationInSubstitution(
|
||||
bound: KotlinType,
|
||||
unsubstitutedArgument: KotlinType,
|
||||
argument: KotlinType,
|
||||
typeParameter: TypeParameterDescriptor
|
||||
) {
|
||||
}
|
||||
|
||||
override fun repeatedAnnotation(annotation: AnnotationDescriptor) {}
|
||||
}
|
||||
}
|
||||
@@ -693,7 +693,7 @@ class CandidateResolver(
|
||||
val typeParameter = typeParameters[i]
|
||||
val substitutedTypeArgument = substitutedTypeProjection.type
|
||||
val unsubstitutedTypeArgument = unsubstitutedType.arguments[i].type
|
||||
DescriptorResolver.checkBoundsInTypeAlias(
|
||||
TypeAliasExpander.checkBoundsInTypeAlias(
|
||||
reportStrategy,
|
||||
unsubstitutedTypeArgument,
|
||||
substitutedTypeArgument,
|
||||
|
||||
Reference in New Issue
Block a user