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))
|
||||
}
|
||||
|
||||
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(
|
||||
c: LazyJavaResolverContext,
|
||||
typeConstructor: () -> TypeConstructor,
|
||||
typeParameterIndex: Int
|
||||
val typeParameter: TypeParameterDescriptor
|
||||
) : 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 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> {
|
||||
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)
|
||||
return javaType.getTypeArguments().withIndices().map {
|
||||
p ->
|
||||
val (i, t) = p
|
||||
transformToTypeProjection(t, howTheProjectionIsUsed.toAttributes(), {getConstructor()}, i)
|
||||
javaTypeParameter ->
|
||||
val (i, t) = javaTypeParameter
|
||||
val parameter = if (i >= typeParameters.size)
|
||||
ErrorUtils.createErrorTypeParameter(i, "#$i for ${typeConstructor}")
|
||||
else typeParameters[i]
|
||||
transformToTypeProjection(t, howTheProjectionIsUsed.toAttributes(), parameter)
|
||||
}.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 {
|
||||
val descriptor = getConstructor().getDeclarationDescriptor()!!
|
||||
|
||||
|
||||
Reference in New Issue
Block a user