Properly transforming type parameters in case of raw types, and mismatches between parameter and argument numbers
NOTE: JetType.getArguments() now implies that JetType.getConstructor() is computed. In most use cases this happens anyways due to the logic of the client code
This commit is contained in:
+62
-32
@@ -76,38 +76,10 @@ class LazyJavaTypeResolver(
|
|||||||
return TypeUtils.makeNullable(KotlinBuiltIns.getInstance().getArrayType(projectionKind, componentType))
|
return TypeUtils.makeNullable(KotlinBuiltIns.getInstance().getArrayType(projectionKind, componentType))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun transformToTypeProjection(
|
|
||||||
javaType: JavaType,
|
|
||||||
attr: JavaTypeAttributes,
|
|
||||||
typeConstructorBeingApplied: () -> TypeConstructor,
|
|
||||||
typeParameterIndex: Int
|
|
||||||
): TypeProjection {
|
|
||||||
return when (javaType) {
|
|
||||||
is JavaWildcardType -> {
|
|
||||||
val bound = javaType.getBound()
|
|
||||||
if (bound == null)
|
|
||||||
LazyStarProjection(c, typeConstructorBeingApplied, typeParameterIndex)
|
|
||||||
else {
|
|
||||||
TypeProjectionImpl(javaType.isExtends().iif(OUT_VARIANCE, IN_VARIANCE), transformJavaType(bound, UPPER_BOUND.toAttributes()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> TypeProjectionImpl(INVARIANT, transformJavaType(javaType, attr))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class LazyStarProjection(
|
private class LazyStarProjection(
|
||||||
c: LazyJavaResolverContext,
|
c: LazyJavaResolverContext,
|
||||||
typeConstructor: () -> TypeConstructor,
|
val typeParameter: TypeParameterDescriptor
|
||||||
typeParameterIndex: Int
|
|
||||||
) : TypeProjectionBase() {
|
) : TypeProjectionBase() {
|
||||||
private val typeParameter by c.storageManager.createLazyValue {
|
|
||||||
val typeConstructor = typeConstructor()
|
|
||||||
val parameters = typeConstructor.getParameters()
|
|
||||||
if (typeParameterIndex >= parameters.size)
|
|
||||||
ErrorUtils.createErrorTypeParameter("#$typeParameterIndex for ${typeConstructor}")
|
|
||||||
else parameters[typeParameterIndex]
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getProjectionKind() = typeParameter.getVariance().eq(OUT_VARIANCE).iif(INVARIANT, OUT_VARIANCE)
|
override fun getProjectionKind() = typeParameter.getVariance().eq(OUT_VARIANCE).iif(INVARIANT, OUT_VARIANCE)
|
||||||
override fun getType() = typeParameter.getUpperBoundsAsType()
|
override fun getType() = typeParameter.getUpperBoundsAsType()
|
||||||
}
|
}
|
||||||
@@ -165,15 +137,73 @@ class LazyJavaTypeResolver(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isRaw(): Boolean {
|
||||||
|
if (javaType.isRaw()) return true
|
||||||
|
|
||||||
|
// This option is needed because sometimes we get weird versions of JDK classes in the class path,
|
||||||
|
// such as collections with no generics, so the Java types are not raw, formally, but they don't match with
|
||||||
|
// their Kotlin analogs, so we treat them as raw to avoid exceptions
|
||||||
|
// No type arguments, but some are expected => raw
|
||||||
|
return javaType.getTypeArguments().isEmpty() && !getConstructor().getParameters().isEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
override fun computeArguments(): List<TypeProjection> {
|
override fun computeArguments(): List<TypeProjection> {
|
||||||
|
val typeConstructor = getConstructor()
|
||||||
|
val typeParameters = typeConstructor.getParameters()
|
||||||
|
if (isRaw()) {
|
||||||
|
return typeParameters.map {
|
||||||
|
parameter ->
|
||||||
|
// not making a star projection because of this case:
|
||||||
|
// Java:
|
||||||
|
// class C<T extends C> {}
|
||||||
|
// The upper bound is raw here, and we can't compute the projection: it would be infinite:
|
||||||
|
// C<*> = C<out C<out C<...>>>
|
||||||
|
// this way we loose some type information, even when the case is not so bad, but it doesn't seem to matter
|
||||||
|
|
||||||
|
// projections are not allowed in immediate arguments of supertypes
|
||||||
|
val projectionKind = if (parameter.getVariance() == OUT_VARIANCE || attr.howThisTypeIsUsed == SUPERTYPE)
|
||||||
|
INVARIANT
|
||||||
|
else OUT_VARIANCE
|
||||||
|
TypeProjectionImpl(projectionKind, KotlinBuiltIns.getInstance().getNullableAnyType())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeParameters.size() != javaType.getTypeArguments().size()) {
|
||||||
|
// Most of the time this means there is an error in the Java code
|
||||||
|
return typeParameters.map { p -> TypeProjectionImpl(ErrorUtils.createErrorType(p.getName().asString())) }
|
||||||
|
}
|
||||||
var howTheProjectionIsUsed = attr.howThisTypeIsUsed.eq(SUPERTYPE).iif(SUPERTYPE_ARGUMENT, TYPE_ARGUMENT)
|
var howTheProjectionIsUsed = attr.howThisTypeIsUsed.eq(SUPERTYPE).iif(SUPERTYPE_ARGUMENT, TYPE_ARGUMENT)
|
||||||
return javaType.getTypeArguments().withIndices().map {
|
return javaType.getTypeArguments().withIndices().map {
|
||||||
p ->
|
javaTypeParameter ->
|
||||||
val (i, t) = p
|
val (i, t) = javaTypeParameter
|
||||||
transformToTypeProjection(t, howTheProjectionIsUsed.toAttributes(), {getConstructor()}, i)
|
val parameter = if (i >= typeParameters.size)
|
||||||
|
ErrorUtils.createErrorTypeParameter(i, "#$i for ${typeConstructor}")
|
||||||
|
else typeParameters[i]
|
||||||
|
transformToTypeProjection(t, howTheProjectionIsUsed.toAttributes(), parameter)
|
||||||
}.toList()
|
}.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun transformToTypeProjection(
|
||||||
|
javaType: JavaType,
|
||||||
|
attr: JavaTypeAttributes,
|
||||||
|
typeParameter: TypeParameterDescriptor
|
||||||
|
): TypeProjection {
|
||||||
|
return when (javaType) {
|
||||||
|
is JavaWildcardType -> {
|
||||||
|
val bound = javaType.getBound()
|
||||||
|
if (bound == null)
|
||||||
|
LazyStarProjection(c, typeParameter)
|
||||||
|
else {
|
||||||
|
var projectionKind = javaType.isExtends().iif(OUT_VARIANCE, IN_VARIANCE)
|
||||||
|
if (projectionKind == typeParameter.getVariance()) {
|
||||||
|
projectionKind = Variance.INVARIANT
|
||||||
|
}
|
||||||
|
TypeProjectionImpl(projectionKind, transformJavaType(bound, UPPER_BOUND.toAttributes()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> TypeProjectionImpl(INVARIANT, transformJavaType(javaType, attr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun computeMemberScope(): JetScope {
|
override fun computeMemberScope(): JetScope {
|
||||||
val descriptor = getConstructor().getDeclarationDescriptor()!!
|
val descriptor = getConstructor().getDeclarationDescriptor()!!
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user