eclipse-archived / ceylon

The Ceylon compiler, language module, and command line tools
http://ceylon-lang.org
Apache License 2.0
399 stars 62 forks source link

Type parameters of interfaces not properly refined in JS backend #6678

Open jvasileff opened 7 years ago

jvasileff commented 7 years ago

Reified type arguments of interfaces that are satisfied multiple times do not properly account for the multiple satisfactions.

For example:

interface I<out T> {
    shared void printT() => print(`T`);
}

class C() satisfies I<Singleton<String>> {}
class D() extends C() satisfies I<Singleton<Integer>> {}

shared void run() {
    C().printT(); // actual: ceylon.language::Singleton<ceylon.language::String> (ok)
    D().printT(); // actual: ceylon.language::Singleton<ceylon.language::String> (bad)
                  // expected: Nothing 
}

making T contravariant (interface I<in T> { ... }) results in:

ceylon.language::Singleton<ceylon.language::String>
ceylon.language::Singleton<ceylon.language::String>

rather than the expected:

ceylon.language::Singleton<ceylon.language::String>
ceylon.language::Singleton<ceylon.language::String>|ceylon.language::Singleton<ceylon.language::Integer>

interestingly, with a covariant T, but type args of String and Integer (no longer boxed with Singleton, the results are:

ceylon.language::String
ceylon.language::String&ceylon.language::Integer

vs. the ideal:

ceylon.language::String
Nothing
chochos commented 7 years ago

Why is the intersection of Singleton<String> and Singleton<Integer> not simply Singleton<String&Integer> and then evaluated to Singleton<Nothing>?

And, are these calculations done at compile time on the JVM backend? Otherwise I have to replicate a lot of stuff in JS...

jvasileff commented 7 years ago

Why is the intersection of Singleton and Singleton not simply Singleton<String&Integer> and then evaluated to Singleton?

Great point @chochos. I think Nothing is probably right because of the "nothing tuples", but the example would be more straight forward if it used class MySingleton<out Element>() {} which I think would result in MySingleton<Nothing> as you suggest.

chochos commented 7 years ago

For type literals I found out the calculation is done at compile time, so the type literalString&Integer is eval'd as Nothing at compile time, which is cool. But for inheritance it looks like it must be done at runtime, but I might be missing something...

chochos commented 7 years ago

Well at least now you get String&Integer, or Singleton<String&Integer> if you still use Singleton.

chochos commented 7 years ago

OK now Singleton<String&Integer> is resolved to Singleton<Nothing>. Getting there.