diff --git a/maddi-cst-print-kotlin/src/main/java/io/codelaser/maddi/cst/print/kotlin/KotlinExpressionPrinter.java b/maddi-cst-print-kotlin/src/main/java/io/codelaser/maddi/cst/print/kotlin/KotlinExpressionPrinter.java index 9e87794b5..3e510d176 100644 --- a/maddi-cst-print-kotlin/src/main/java/io/codelaser/maddi/cst/print/kotlin/KotlinExpressionPrinter.java +++ b/maddi-cst-print-kotlin/src/main/java/io/codelaser/maddi/cst/print/kotlin/KotlinExpressionPrinter.java @@ -313,7 +313,10 @@ private static OutputBuilder methodCall(MethodCall mc, Qualification q) { .add(SymbolEnum.DOT).add(new TextImpl(mc.methodInfo().name())) .add(arguments(mc.parameterExpressions(), mc.methodInfo(), q)); } - if (object != null && !mc.objectIsImplicit() && expectedElement(mc) == null && (toArrayOf(mc.methodInfo()) + // super.toArray() in a subclass of a Java collection class (AbstractCollection): Kotlin sees Java's toArray as + // the superclass's member, and `super` is no value to cast or to call an extension on + boolean onSuper = object instanceof VariableExpression sv && sv.variable() instanceof This st && st.writeSuper(); + if (object != null && !mc.objectIsImplicit() && !onSuper && expectedElement(mc) == null && (toArrayOf(mc.methodInfo()) && mc.parameterExpressions().getFirst().parameterizedType() != null && mc.parameterExpressions().getFirst().parameterizedType().arrays() == 1 && mc.parameterExpressions().getFirst().parameterizedType().componentType().typeParameter() != null @@ -379,7 +382,7 @@ private static OutputBuilder methodCall(MethodCall mc, Qualification q) { if (KotlinMappedMembers.isRemoveAt(mc.methodInfo())) { return b.add(new TextImpl("removeAt")).add(arguments(mc.parameterExpressions(), q)); } - if (toArrayOf(mc.methodInfo()) && object != null && !mc.objectIsImplicit()) { + if (toArrayOf(mc.methodInfo()) && object != null && !mc.objectIsImplicit() && !onSuper) { // c.toArray(new X[0]): Kotlin's collections have no toArray(T[]); toTypedArray() types the array as // Java's argument does (Kotlin's arrays are invariant, its Collection is not), with the element // state of what it initializes @@ -390,7 +393,7 @@ private static OutputBuilder methodCall(MethodCall mc, Qualification q) { .withNullable(io.codelaser.maddi.cst.api.type.NullableState.NONNULL), q); return b.add(new TextImpl(element == null ? "toTypedArray()" : "toTypedArray<" + element + ">()")); } - if (toArray(mc.methodInfo()) && object != null && !mc.objectIsImplicit()) { + if (toArray(mc.methodInfo()) && object != null && !mc.objectIsImplicit() && !onSuper) { // c.toArray(): Kotlin's collections have no toArray() either. toTypedArray() or (), as Java's // Object[] prints here (a Collection is a Collection of either): typed by the collection, a local // would be an Array where Java declares an Object[] diff --git a/maddi-cst-print-kotlin/src/test/java/io/codelaser/maddi/cst/print/kotlin/TestJavaToKotlinStructure.java b/maddi-cst-print-kotlin/src/test/java/io/codelaser/maddi/cst/print/kotlin/TestJavaToKotlinStructure.java index aa0bac386..ba3243d1a 100644 --- a/maddi-cst-print-kotlin/src/test/java/io/codelaser/maddi/cst/print/kotlin/TestJavaToKotlinStructure.java +++ b/maddi-cst-print-kotlin/src/test/java/io/codelaser/maddi/cst/print/kotlin/TestJavaToKotlinStructure.java @@ -1974,6 +1974,29 @@ abstract class Fwd implements Collection { compiles(kotlin); } + /** + * A subclass of AbstractCollection, a Java class: Kotlin sees its toArray() and toArray(T[]) as members, so + * {@code super.toArray()} stays a call to the superclass's member. Kotlin's {@code super} is no value: it can be + * neither cast ({@code (super as java.util.Collection<*>)}) nor the receiver of the extension toTypedArray. + */ + @Test + public void toArrayOnSuper() { + String kotlin = kotlin(""" + package a; + import java.util.*; + class Bag extends AbstractCollection { + private final List items = new ArrayList<>(); + @Override public Iterator iterator() { return items.iterator(); } + @Override public int size() { return items.size(); } + @Override public Object[] toArray() { return super.toArray(); } + @Override public T[] toArray(T[] array) { return super.toArray(array); } + } + """); + contains(kotlin, "super.toArray()"); + contains(kotlin, "super.toArray(array)"); + compiles(kotlin); + } + /** * guava's Optional.toJavaUtil(), AbstractValueGraph.edgeValue: java.util.Optional.ofNullable(t) into an * Optional. Kotlin's Optional bounds its T non-null, so the call is an Optional; the cast is unchecked.