Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ private static String base(ParameterizedType pt, Qualification q) {
String base = mapped(fqn);
if (base == null) base = name(pt.typeInfo(), q);
if (pt.parameters().isEmpty()) return base + starProjections(pt.typeInfo());
String inner = innerWithOuterArguments(pt, q);
if (inner != null) return inner;
StringBuilder sb = new StringBuilder(base).append('<');
for (int i = 0; i < pt.parameters().size(); i++) {
if (i > 0) sb.append(", ");
Expand All @@ -205,6 +207,30 @@ private static String base(ParameterizedType pt, Qualification q) {
return sb.append('>').toString();
}

/**
* {@code G<String>.In}: an inner class whose {@code parameters()} start with its outer classes' type arguments,
* each written on its own class, as Java's printer distributes them. Null when the type has only its own.
*/
private static String innerWithOuterArguments(ParameterizedType pt, Qualification q) {
TypeInfo t = pt.typeInfo();
int end = pt.parameters().size();
if (!t.isInnerClass() || end <= t.typeParameters().size()) return null;
java.util.List<String> segments = new java.util.ArrayList<>();
while (true) {
int own = t.typeParameters().size();
if (own > end) return null;
java.util.List<ParameterizedType> args = pt.parameters().subList(end - own, end);
end -= own;
TypeInfo outer = t.enclosingTypeStream().skip(1).findFirst().orElse(null);
boolean first = end == 0 || !t.isInnerClass() || outer == null;
String head = first ? name(t, q) : KotlinNames.name(t.simpleName());
segments.addFirst(args.isEmpty() ? head
: head + args.stream().map(a -> of(a, q)).collect(Collectors.joining(", ", "<", ">")));
if (first) return end == 0 ? String.join(".", segments) : null;
t = outer;
}
}

private static String withoutWildcard(ParameterizedType pt, Qualification q) {
if (pt.isTypeParameter()) return pt.typeParameter().simpleName();
String base = mapped(pt.typeInfo().fullyQualifiedName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1733,6 +1733,28 @@ abstract class Cache<K, V> extends AbstractMap<K, V> {
compiles(kotlin);
}

/**
* An inner class of a generic class named outside it, {@code G<String>.In}: Kotlin's type has the outer class's
* type argument on the outer class too. {@code G.In} lacks it ("one type argument expected").
*/
@Test
public void innerOfGenericClassNamedOutsideIt() {
String kotlin = kotlin("""
package a;
class Top {
static class G<K> {
K last;
class In { K get() { return last; } }
}
static class C {
String pass(G<String>.In x) { return x.get(); }
}
}
""");
contains(kotlin, "x: G<String>.In");
compiles(kotlin);
}

/**
* guava's Maps.FilteredEntrySortedMap.SortedKeySet extends FilteredEntryMap's inner KeySet: an inner class whose
* superclass is an inner class of a generic superclass of its outer class.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1976,6 +1976,16 @@ private ParameterizedType convertTreeDontSet(Tree type, DetailedSources.Builder
assert pt != null;
TypeInfo ti = pt.typeInfo();
assert ti != null;
// G<String>.In, an inner class named through a parameterized outer type: the outer type's arguments come
// first in parameters(), as the bytecode inspector has them (ParameterizedTypePrinter.distributeTypeParameters).
// javac's type of In carries them only on its enclosing type (a class type only for an inner class), which
// classType does not look at.
if (fieldAccess.type instanceof Type.ClassType ct
&& ct.getEnclosingType() instanceof Type.ClassType outer && outer.isParameterized()) {
List<ParameterizedType> parameters = new ArrayList<>(convert(outer).parameters());
parameters.addAll(pt.parameters());
pt = runtime.newParameterizedType(ti, parameters);
}
dsb.put(ti, source);
iterateUpToPackageLevel(dsb, fieldAccess, ti);
return pt;
Expand Down
Loading