Move type enhacement parts to separate package in runtime
It's needed to enhace types when loading descriptors via reflection. Also get rid of `enhanceSignatures` method in ExternalSignatureResolver as enhancement does not use external signature at all
This commit is contained in:
-13
@@ -18,14 +18,12 @@ package org.jetbrains.kotlin.load.java.components;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.ReadOnly;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaField;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaMember;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaMethod;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -75,11 +73,6 @@ public interface ExternalSignatureResolver {
|
||||
public void reportSignatureErrors(@NotNull CallableMemberDescriptor descriptor, @NotNull List<String> signatureErrors) {
|
||||
throw new UnsupportedOperationException("Should not be called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <D extends CallableMemberDescriptor> Collection<D> enhanceSignatures(@NotNull @ReadOnly Collection<D> platformSignatures) {
|
||||
return platformSignatures;
|
||||
}
|
||||
};
|
||||
|
||||
abstract class MemberSignature {
|
||||
@@ -208,10 +201,4 @@ public interface ExternalSignatureResolver {
|
||||
);
|
||||
|
||||
void reportSignatureErrors(@NotNull CallableMemberDescriptor descriptor, @NotNull List<String> signatureErrors);
|
||||
|
||||
/**
|
||||
* Replaces some items in the {@code platformSignatures} collection with enhanced signatures.
|
||||
* Is called after binding overrides, so the implementation is allowed to inspect contents of getOverriddenDescriptors()
|
||||
*/
|
||||
<D extends CallableMemberDescriptor> Collection<D> enhanceSignatures(@NotNull @ReadOnly Collection<D> platformSignatures);
|
||||
}
|
||||
|
||||
+4
-5
@@ -35,16 +35,15 @@ import org.jetbrains.kotlin.load.java.structure.JavaArrayType
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaConstructor
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaMethod
|
||||
import org.jetbrains.kotlin.load.java.structure.*
|
||||
import org.jetbrains.kotlin.load.java.typeEnhacement.enhanceSignatures
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorFactory
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.emptyOrSingletonList
|
||||
import org.jetbrains.kotlin.utils.ifEmpty
|
||||
import org.jetbrains.kotlin.utils.valuesToMap
|
||||
import org.jetbrains.kotlin.utils.*
|
||||
import java.util.ArrayList
|
||||
import java.util.Collections
|
||||
import java.util.LinkedHashSet
|
||||
@@ -72,7 +71,7 @@ public class LazyJavaClassMemberScope(
|
||||
result.addIfNotNull(c.samConversionResolver.resolveSamAdapter(descriptor))
|
||||
}
|
||||
|
||||
c.externalSignatureResolver.enhanceSignatures(
|
||||
enhanceSignatures(
|
||||
result ifEmpty { emptyOrSingletonList(createDefaultConstructor()) }
|
||||
).toReadOnlyList()
|
||||
}
|
||||
|
||||
+3
-2
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.load.java.structure.JavaArrayType
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaField
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaMethod
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaValueParameter
|
||||
import org.jetbrains.kotlin.load.java.typeEnhacement.enhanceSignatures
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.jvm.PLATFORM_TYPES
|
||||
@@ -86,7 +87,7 @@ public abstract class LazyJavaMemberScope(
|
||||
|
||||
computeNonDeclaredFunctions(result, name)
|
||||
|
||||
val enhancedResult = c.externalSignatureResolver.enhanceSignatures(result)
|
||||
val enhancedResult = enhanceSignatures(result)
|
||||
|
||||
// Make sure that lazy things are computed before we release the lock
|
||||
for (f in enhancedResult) {
|
||||
@@ -239,7 +240,7 @@ public abstract class LazyJavaMemberScope(
|
||||
if (DescriptorUtils.isAnnotationClass(containingDeclaration))
|
||||
properties.toReadOnlyList()
|
||||
else
|
||||
c.externalSignatureResolver.enhanceSignatures(properties).toReadOnlyList()
|
||||
enhanceSignatures(properties).toReadOnlyList()
|
||||
}
|
||||
|
||||
private fun resolveProperty(field: JavaField): PropertyDescriptor {
|
||||
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.load.java.typeEnhacement
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.load.java.typeEnhacement.computeIndexedQualifiersForOverride
|
||||
import org.jetbrains.kotlin.load.java.typeEnhacement.enhance
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
|
||||
fun <D : CallableMemberDescriptor> enhanceSignatures(platformSignatures: Collection<D>): Collection<D> {
|
||||
return platformSignatures.map {
|
||||
it.enhance()
|
||||
}
|
||||
}
|
||||
|
||||
fun <D : CallableMemberDescriptor> D.enhance(): D {
|
||||
// TODO type parameters
|
||||
// TODO use new type parameters while enhancing other types
|
||||
// TODO Propagation into generic type arguments
|
||||
|
||||
val enhancedReceiverType =
|
||||
if (getExtensionReceiverParameter() != null)
|
||||
parts { it.getExtensionReceiverParameter()!!.toPart() }.enhance()
|
||||
else null
|
||||
|
||||
val enhancedValueParameters = getValueParameters().map {
|
||||
p -> parts { it.getValueParameters()[p.getIndex()]!!.toPart() }.enhance()
|
||||
}
|
||||
|
||||
val enhancedReturnType = parts { it.getReturnType()!!.toReturnTypePart() }.enhance()
|
||||
|
||||
if (this is JavaCallableMemberDescriptor) {
|
||||
@suppress("UNCHECKED_CAST")
|
||||
return this.enhance(enhancedReceiverType, enhancedValueParameters, enhancedReturnType) as D
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
fun <T, P : SignaturePart<T>> SignatureParts<T, P>.enhance(): T {
|
||||
val qualifiers = fromOverride.type.computeIndexedQualifiersForOverride(this.fromOverridden.map { it.type }, fromOverride.isCovariant)
|
||||
return fromOverride.replaceType(fromOverride.type.enhance(qualifiers))
|
||||
}
|
||||
|
||||
class SignatureParts<T, P: SignaturePart<T>>(
|
||||
val fromOverride: P,
|
||||
val fromOverridden: Collection<P>
|
||||
)
|
||||
|
||||
interface SignaturePart<out T> {
|
||||
val isCovariant: Boolean
|
||||
get() = false
|
||||
|
||||
val type: JetType
|
||||
|
||||
fun replaceType(newType: JetType): T
|
||||
}
|
||||
|
||||
fun ReceiverParameterDescriptor.toPart() = object : SignaturePart<JetType> {
|
||||
override val type = this@toPart.getType() // workaround for KT-7557
|
||||
|
||||
override fun replaceType(newType: JetType) = newType
|
||||
}
|
||||
|
||||
fun ValueParameterDescriptor.toPart() = object : SignaturePart<ValueParameterDescriptor> {
|
||||
override val type = this@toPart.getType() // workaround for KT-7557
|
||||
|
||||
override fun replaceType(newType: JetType) = ValueParameterDescriptorImpl(
|
||||
getContainingDeclaration(),
|
||||
null,
|
||||
getIndex(),
|
||||
getAnnotations(),
|
||||
getName(),
|
||||
newType,
|
||||
declaresDefaultValue(),
|
||||
if (getVarargElementType() != null) KotlinBuiltIns.getInstance().getArrayElementType(newType) else null,
|
||||
getSource()
|
||||
)
|
||||
}
|
||||
|
||||
fun JetType.toReturnTypePart() = object : SignaturePart<JetType> {
|
||||
override val type = this@toReturnTypePart
|
||||
|
||||
override val isCovariant: Boolean = true
|
||||
|
||||
override fun replaceType(newType: JetType) = newType
|
||||
}
|
||||
|
||||
fun <D : CallableMemberDescriptor, T, P : SignaturePart<T>> D.parts(collector: (D) -> P): SignatureParts<T, P> {
|
||||
return SignatureParts(
|
||||
collector(this),
|
||||
this.getOverriddenDescriptors().map {
|
||||
@suppress("UNCHECKED_CAST")
|
||||
collector(it as D)
|
||||
}
|
||||
)
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.load.java.typeEnhacement
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.load.java.typeEnhacement.JavaTypeQualifiers
|
||||
import org.jetbrains.kotlin.load.java.typeEnhacement.MutabilityQualifier.MUTABLE
|
||||
import org.jetbrains.kotlin.load.java.typeEnhacement.MutabilityQualifier.READ_ONLY
|
||||
import org.jetbrains.kotlin.load.java.typeEnhacement.NullabilityQualifier.NOT_NULL
|
||||
import org.jetbrains.kotlin.load.java.typeEnhacement.NullabilityQualifier.NULLABLE
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.types.*
|
||||
|
||||
// The index in the lambda is the position of the type component:
|
||||
// Example: for `A<B, C<D, E>>`, indices go as follows: `0 - A<...>, 1 - B, 2 - C<D, E>, 3 - D, 4 - E`,
|
||||
// which corresponds to the left-to-right breadth-first walk of the tree representation of the type.
|
||||
// For flexible types, both bounds are indexed in the same way: `(A<B>..C<D>)` gives `0 - (A<B>..C<D>), 1 - B and D`.
|
||||
fun JetType.enhance(qualifiers: (Int) -> JavaTypeQualifiers) = this.enhancePossiblyFlexible(qualifiers, 0).type
|
||||
|
||||
|
||||
private enum class TypeComponentPosition {
|
||||
FLEXIBLE_LOWER,
|
||||
FLEXIBLE_UPPER,
|
||||
INFLEXIBLE
|
||||
}
|
||||
|
||||
data class Result(val type: JetType, val subtreeSize: Int)
|
||||
|
||||
private fun JetType.enhancePossiblyFlexible(qualifiers: (Int) -> JavaTypeQualifiers, index: Int): Result {
|
||||
if (this.isError()) return Result(this, 1)
|
||||
return if (this.isFlexible()) {
|
||||
with(this.flexibility()) {
|
||||
val lowerResult = lowerBound.enhanceInflexible(qualifiers, index, TypeComponentPosition.FLEXIBLE_LOWER)
|
||||
val upperResult = upperBound.enhanceInflexible(qualifiers, index, TypeComponentPosition.FLEXIBLE_UPPER)
|
||||
assert(lowerResult.subtreeSize == upperResult.subtreeSize) {
|
||||
"Different tree sizes of bounds: " +
|
||||
"lower = ($lowerBound, ${lowerResult.subtreeSize}), " +
|
||||
"upper = ($upperBound, ${upperResult.subtreeSize})"
|
||||
}
|
||||
Result(
|
||||
DelegatingFlexibleType.create(lowerResult.type, upperResult.type, extraCapabilities), lowerResult.subtreeSize
|
||||
)
|
||||
}
|
||||
}
|
||||
else this.enhanceInflexible(qualifiers, index, TypeComponentPosition.INFLEXIBLE)
|
||||
}
|
||||
|
||||
private fun JetType.enhanceInflexible(qualifiers: (Int) -> JavaTypeQualifiers, index: Int, position: TypeComponentPosition): Result {
|
||||
val shouldEnhance = position.shouldEnhance()
|
||||
if (!shouldEnhance && getArguments().isEmpty()) return Result(this, 1)
|
||||
|
||||
val originalClass = getConstructor().getDeclarationDescriptor()
|
||||
?: return Result(this, 1)
|
||||
|
||||
val effectiveQualifiers = qualifiers(index)
|
||||
val enhancedClassifier = originalClass.enhanceMutability(effectiveQualifiers, position)
|
||||
|
||||
var globalArgIndex = index + 1
|
||||
val enhancedArguments = getArguments().mapIndexed {
|
||||
localArgIndex, arg ->
|
||||
if (arg.isStarProjection()) {
|
||||
globalArgIndex++
|
||||
TypeUtils.makeStarProjection(enhancedClassifier.getTypeConstructor().getParameters()[localArgIndex])
|
||||
}
|
||||
else {
|
||||
val (enhancedType, subtreeSize) = arg.getType().enhancePossiblyFlexible(qualifiers, globalArgIndex)
|
||||
globalArgIndex += subtreeSize
|
||||
TypeProjectionImpl(
|
||||
arg.getProjectionKind(),
|
||||
enhancedType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val enhancedType = JetTypeImpl(
|
||||
getAnnotations(),
|
||||
enhancedClassifier.getTypeConstructor(),
|
||||
this.getEnhancedNullability(effectiveQualifiers, position),
|
||||
enhancedArguments,
|
||||
if (enhancedClassifier is ClassDescriptor)
|
||||
enhancedClassifier.getMemberScope(enhancedArguments)
|
||||
else enhancedClassifier.getDefaultType().getMemberScope()
|
||||
)
|
||||
return Result(enhancedType, globalArgIndex - index)
|
||||
}
|
||||
|
||||
private fun TypeComponentPosition.shouldEnhance() = this != TypeComponentPosition.INFLEXIBLE
|
||||
|
||||
private fun ClassifierDescriptor.enhanceMutability(qualifiers: JavaTypeQualifiers, position: TypeComponentPosition): ClassifierDescriptor {
|
||||
if (!position.shouldEnhance()) return this
|
||||
if (this !is ClassDescriptor) return this // mutability is not applicable for type parameters
|
||||
|
||||
val mapping = JavaToKotlinClassMap.INSTANCE
|
||||
|
||||
when (qualifiers.mutability) {
|
||||
READ_ONLY -> {
|
||||
if (position == TypeComponentPosition.FLEXIBLE_LOWER && mapping.isMutable(this)) {
|
||||
return mapping.convertMutableToReadOnly(this)
|
||||
}
|
||||
}
|
||||
MUTABLE -> {
|
||||
if (position == TypeComponentPosition.FLEXIBLE_UPPER && mapping.isReadOnly(this) ) {
|
||||
return mapping.convertReadOnlyToMutable(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
private fun JetType.getEnhancedNullability(qualifiers: JavaTypeQualifiers, position: TypeComponentPosition): Boolean {
|
||||
if (!position.shouldEnhance()) return this.isMarkedNullable()
|
||||
|
||||
return when (qualifiers.nullability) {
|
||||
NULLABLE -> true
|
||||
NOT_NULL -> false
|
||||
else -> this.isMarkedNullable()
|
||||
}
|
||||
}
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.load.java.typeEnhacement
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.java.typeEnhacement.MutabilityQualifier.MUTABLE
|
||||
import org.jetbrains.kotlin.load.java.typeEnhacement.MutabilityQualifier.READ_ONLY
|
||||
import org.jetbrains.kotlin.load.java.typeEnhacement.NullabilityQualifier.NOT_NULL
|
||||
import org.jetbrains.kotlin.load.java.typeEnhacement.NullabilityQualifier.NULLABLE
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker
|
||||
import org.jetbrains.kotlin.types.flexibility
|
||||
import org.jetbrains.kotlin.types.isFlexible
|
||||
import org.jetbrains.kotlin.utils.getOrDefault
|
||||
import java.util.ArrayList
|
||||
|
||||
enum class NullabilityQualifier {
|
||||
NULLABLE,
|
||||
NOT_NULL
|
||||
}
|
||||
|
||||
val NULLABLE_ANNOTATIONS = listOf(
|
||||
JvmAnnotationNames.JETBRAINS_NULLABLE_ANNOTATION
|
||||
)
|
||||
|
||||
val NOT_NULL_ANNOTATIONS = listOf(
|
||||
JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION
|
||||
)
|
||||
|
||||
enum class MutabilityQualifier {
|
||||
READ_ONLY,
|
||||
MUTABLE
|
||||
}
|
||||
|
||||
val READ_ONLY_ANNOTATIONS = listOf(
|
||||
JvmAnnotationNames.JETBRAINS_READONLY_ANNOTATION
|
||||
)
|
||||
|
||||
val MUTABLE_ANNOTATIONS = listOf(
|
||||
JvmAnnotationNames.JETBRAINS_MUTABLE_ANNOTATION
|
||||
)
|
||||
|
||||
class JavaTypeQualifiers(
|
||||
val nullability: NullabilityQualifier?,
|
||||
val mutability: MutabilityQualifier?
|
||||
) {
|
||||
companion object {
|
||||
val NONE = JavaTypeQualifiers(null, null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun JetType.extractQualifiers(): JavaTypeQualifiers {
|
||||
val (lower, upper) =
|
||||
if (this.isFlexible())
|
||||
flexibility().let { Pair(it.lowerBound, it.upperBound) }
|
||||
else Pair(this, this)
|
||||
|
||||
val mapping = JavaToKotlinClassMap.INSTANCE
|
||||
return JavaTypeQualifiers(
|
||||
if (lower.isMarkedNullable()) NULLABLE else if (!upper.isMarkedNullable()) NOT_NULL else null,
|
||||
if (mapping.isReadOnly(lower)) READ_ONLY else if (mapping.isMutable(upper)) MUTABLE else null
|
||||
)
|
||||
}
|
||||
|
||||
private fun Annotations.extractQualifiers(): JavaTypeQualifiers {
|
||||
fun <T: Any> List<FqName>.ifPresent(qualifier: T) = if (any { findAnnotation(it) != null}) qualifier else null
|
||||
fun <T: Any> singleNotNull(x: T?, y: T?) = if (x == null || y == null) x ?: y else null
|
||||
|
||||
return JavaTypeQualifiers(
|
||||
singleNotNull(NULLABLE_ANNOTATIONS.ifPresent(NULLABLE), NOT_NULL_ANNOTATIONS.ifPresent(NOT_NULL)),
|
||||
singleNotNull(READ_ONLY_ANNOTATIONS.ifPresent(READ_ONLY), MUTABLE_ANNOTATIONS.ifPresent(MUTABLE))
|
||||
)
|
||||
}
|
||||
|
||||
fun JetType.computeIndexedQualifiersForOverride(fromSupertypes: Collection<JetType>, isCovariant: Boolean): (Int) -> JavaTypeQualifiers {
|
||||
fun JetType.toIndexed(): List<JetType> {
|
||||
val list = ArrayList<JetType>(1)
|
||||
|
||||
fun add(type: JetType) {
|
||||
list.add(type)
|
||||
for (arg in type.getArguments()) {
|
||||
if (arg.isStarProjection()) {
|
||||
list.add(arg.getType())
|
||||
}
|
||||
else {
|
||||
add(arg.getType())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add(this)
|
||||
return list
|
||||
}
|
||||
|
||||
val indexedFromSupertypes = fromSupertypes.map { it.toIndexed() }
|
||||
val indexedThisType = this.toIndexed()
|
||||
|
||||
// The covariant case may be hard, e.g. in the superclass the return may be Super<T>, but in the subclass it may be Derived, which
|
||||
// is declared to extend Super<T>, and propagating data here is highly non-trivial, so we only look at the head type constructor
|
||||
// (outermost type), unless the type in the subclass is interchangeable with the all the types in superclasses:
|
||||
// e.g. we have (Mutable)List<String!>! in the subclass and { List<String!>, (Mutable)List<String>! } from superclasses
|
||||
// Note that `this` is flexible here, so it's equal to it's bounds
|
||||
val onlyHeadTypeConstructor = isCovariant && fromSupertypes.any { !JetTypeChecker.DEFAULT.equalTypes(it, this) }
|
||||
|
||||
return fun(index: Int): JavaTypeQualifiers {
|
||||
val isHeadTypeConstructor = index == 0
|
||||
if (!isHeadTypeConstructor && onlyHeadTypeConstructor) return JavaTypeQualifiers.NONE
|
||||
|
||||
val qualifiers = indexedThisType.getOrDefault(index, { return JavaTypeQualifiers.NONE })
|
||||
val verticalSlice = indexedFromSupertypes.map { it.getOrDefault(index, { null }) }.filterNotNull()
|
||||
|
||||
// Only the head type constructor is safely co-variant
|
||||
return qualifiers.computeQualifiersForOverride(verticalSlice, isCovariant && isHeadTypeConstructor)
|
||||
}
|
||||
}
|
||||
|
||||
private fun JetType.computeQualifiersForOverride(fromSupertypes: Collection<JetType>, isCovariant: Boolean): JavaTypeQualifiers {
|
||||
val nullabilityFromSupertypes = fromSupertypes.map { it.extractQualifiers().nullability }.filterNotNull().toSet()
|
||||
val mutabilityFromSupertypes = fromSupertypes.map { it.extractQualifiers().mutability }.filterNotNull().toSet()
|
||||
val own = getAnnotations().extractQualifiers()
|
||||
|
||||
if (isCovariant) {
|
||||
fun <T : Any> Set<T>.selectCovariantly(low: T, high: T, own: T?): T? {
|
||||
val supertypeQualifier = if (low in this) low else if (high in this) high else null
|
||||
return if (supertypeQualifier == low && own == high) null else own ?: supertypeQualifier
|
||||
}
|
||||
return JavaTypeQualifiers(
|
||||
nullabilityFromSupertypes.selectCovariantly(NOT_NULL, NULLABLE, own.nullability),
|
||||
mutabilityFromSupertypes.selectCovariantly(MUTABLE, READ_ONLY, own.mutability)
|
||||
)
|
||||
}
|
||||
else {
|
||||
fun <T : Any> Set<T>.selectInvariantly(own: T?): T? {
|
||||
val effectiveSet = own?.let { (this + own).toSet() } ?: this
|
||||
// if this set contains exactly one element, it is the qualifier everybody agrees upon,
|
||||
// otherwise (no qualifiers, or multiple qualifiers), there's no single such qualifier
|
||||
// and all qualifiers are discarded
|
||||
return effectiveSet.singleOrNull()
|
||||
}
|
||||
return JavaTypeQualifiers(
|
||||
nullabilityFromSupertypes.selectInvariantly(own.nullability),
|
||||
mutabilityFromSupertypes.selectInvariantly(own.mutability)
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user