Support generic constructors defined in Java

#KT-10686 Fixed
 #KT-10410 Fixed
This commit is contained in:
Denis Zharkov
2016-01-22 16:02:46 +03:00
parent a02d1b75b8
commit 6542d091ee
32 changed files with 353 additions and 55 deletions
@@ -75,5 +75,6 @@ fun LazyJavaResolverContext.child(
fun LazyJavaResolverContext.child(
containingDeclaration: DeclarationDescriptor,
typeParameterOwner: JavaTypeParameterListOwner
) = this.child(LazyJavaTypeParameterResolver(this, containingDeclaration, typeParameterOwner))
typeParameterOwner: JavaTypeParameterListOwner,
typeParametersIndexOffset: Int = 0
) = this.child(LazyJavaTypeParameterResolver(this, containingDeclaration, typeParameterOwner, typeParametersIndexOffset))
@@ -506,9 +506,14 @@ class LazyJavaClassMemberScope(
classDescriptor, c.resolveAnnotations(constructor), /* isPrimary = */ false, c.components.sourceElementFactory.source(constructor)
)
val valueParameters = resolveValueParameters(c, constructorDescriptor, constructor.valueParameters)
constructorDescriptor.initialize(valueParameters.descriptors, constructor.visibility)
val c = c.child(constructorDescriptor, constructor, typeParametersIndexOffset = classDescriptor.declaredTypeParameters.size)
val valueParameters = resolveValueParameters(c, constructorDescriptor, constructor.valueParameters)
val constructorTypeParameters =
classDescriptor.declaredTypeParameters +
constructor.typeParameters.map { p -> c.typeParameterResolver.resolveTypeParameter(p)!! }
constructorDescriptor.initialize(valueParameters.descriptors, constructor.visibility, constructorTypeParameters)
constructorDescriptor.setHasStableParameterNames(false)
constructorDescriptor.setHasSynthesizedParameterNames(valueParameters.hasSynthesizedNames)
@@ -43,14 +43,15 @@ interface TypeParameterResolver {
class LazyJavaTypeParameterResolver(
private val c: LazyJavaResolverContext,
private val containingDeclaration: DeclarationDescriptor,
typeParameterOwner: JavaTypeParameterListOwner
typeParameterOwner: JavaTypeParameterListOwner,
private val typeParametersIndexOffset: Int
) : TypeParameterResolver {
private val typeParameters: Map<JavaTypeParameter, Int> = typeParameterOwner.typeParameters.mapToIndex()
private val resolve = c.storageManager.createMemoizedFunctionWithNullableValues {
typeParameter: JavaTypeParameter ->
typeParameters[typeParameter]?.let { index ->
LazyJavaTypeParameterDescriptor(c.child(this), typeParameter, index, containingDeclaration)
LazyJavaTypeParameterDescriptor(c.child(this), typeParameter, typeParametersIndexOffset + index, containingDeclaration)
}
}
@@ -116,13 +116,8 @@ class LazyJavaTypeResolver(
?: ErrorUtils.createErrorTypeConstructor("Unresolved java classifier: " + javaType.presentableText)
}
is JavaTypeParameter -> {
if (isConstructorTypeParameter()) {
getConstructorTypeParameterSubstitute().getConstructor()
}
else {
typeParameterResolver.resolveTypeParameter(classifier)?.typeConstructor
?: ErrorUtils.createErrorTypeConstructor("Unresolved Java type parameter: " + javaType.presentableText)
}
typeParameterResolver.resolveTypeParameter(classifier)?.typeConstructor
?: ErrorUtils.createErrorTypeConstructor("Unresolved Java type parameter: " + javaType.presentableText)
}
else -> throw IllegalStateException("Unknown classifier kind: $classifier")
}
@@ -158,24 +153,6 @@ class LazyJavaTypeResolver(
return kotlinDescriptor
}
private fun isConstructorTypeParameter(): Boolean {
val classifier = classifier()
return classifier is JavaTypeParameter && classifier.getOwner() is JavaConstructor
}
// We do not memoize the results of this method, because it would consume much memory, and the real gain is little:
// the case this method accounts for is very rare, no point in optimizing it
private fun getConstructorTypeParameterSubstitute(): KotlinType {
// If a Java constructor declares its own type parameters, we have no way of directly expressing them in Kotlin,
// so we replace each type parameter with its representative upper bound (which in Java is also the first bound)
val upperBounds = (classifier() as JavaTypeParameter).upperBounds
if (upperBounds.isEmpty()) {
return c.module.builtIns.nullableAnyType
}
return transformJavaType(upperBounds.first(), UPPER_BOUND.toAttributes())
}
private fun isRaw(): Boolean {
if (javaType.isRaw) return true
@@ -212,9 +189,6 @@ class LazyJavaTypeResolver(
RawSubstitution.computeProjection(parameter, attr, erasedUpperBound)
}
}
if (isConstructorTypeParameter()) {
return getConstructorTypeParameterSubstitute().getArguments()
}
if (typeParameters.size != javaType.typeArguments.size) {
// Most of the time this means there is an error in the Java code
@@ -265,10 +239,7 @@ class LazyJavaTypeResolver(
// nullability will be taken care of in individual member signatures
when (classifier()) {
is JavaTypeParameter -> {
if (isConstructorTypeParameter())
getConstructorTypeParameterSubstitute().isMarkedNullable()
else
attr.howThisTypeIsUsed !in setOf(TYPE_ARGUMENT, UPPER_BOUND, SUPERTYPE_ARGUMENT, SUPERTYPE)
attr.howThisTypeIsUsed !in setOf(TYPE_ARGUMENT, UPPER_BOUND, SUPERTYPE_ARGUMENT, SUPERTYPE)
}
is JavaClass,
null -> attr.howThisTypeIsUsed !in setOf(TYPE_ARGUMENT, SUPERTYPE_ARGUMENT, SUPERTYPE)