ceylon icon indicating copy to clipboard operation
ceylon copied to clipboard

backend visibility error calling java.lang.StringBuilder.length()

Open jvasileff opened this issue 8 years ago • 2 comments

StringBuilder.length() is defined by the non-visible AbstractStringBuilder, and normally AbstractStringBuilder.length() would not be visible.

But due to Java's visibility rules, AbstractStringBuilder.length() is visible when accessed via the public StringBuilder which extends AbstractStringBuilder.

Usually the backend cooperates (perhaps by chance?) and casts the receiver to StringBuilder, but I it is possible to trip it up. In the code below, length's defining class (AbstractStringBuilder) is used:

import java.lang { StringBuilder }

shared void run() {
    printLength(StringBuilder());
}

void printLength<T>(T t) given T satisfies StringBuilder {
    print(t.length());
}

// source/simple/run.ceylon:8: error: Ceylon backend error: AbstractStringBuilder is not public in java.lang; cannot be accessed from outside package
//     print(t.length());
//           ^

as we can see:

.ceylon.language.print_.print(.ceylon.language.Integer.instance(((.java.lang.AbstractStringBuilder)t).length()));

jvasileff avatar Oct 10 '17 22:10 jvasileff

Sounds like it could be fixed by removal of the unnecessary typecast to AbstractStringBuilder.

gavinking avatar Oct 11 '17 09:10 gavinking

Not that I think this issue is all that critical (I imagine it's pretty rare), but... come to think of it, a generalized solution isn't that straight forward.

Given:

  • protected class A with member public foo()
  • public class B extends A
  • public class C extends A

In Ceylon, you might have (o of <B|C>).foo(). In the generated Java code, you'd have to have if (o instanceof B) ((B)o).foo() else ((C)o).foo()

So I think it would be:

  • If the Ceylon receiver type extends a class or interface that is a) accessible and b) inherits the member-to-invoke's container, use it. Otherwise,
  • a union must be involved, so switch over all of the possible public types that inherit the member-to-invoke's container.

jvasileff avatar Oct 11 '17 16:10 jvasileff