thheller / shadow-cljs

ClojureScript compilation made easy
https://github.com/thheller/shadow-cljs
Eclipse Public License 1.0
2.23k stars 173 forks source link

defclass can't call super in Object methods #1137

Open thheller opened 11 months ago

thheller commented 11 months ago
(defclass A
  (constructor [this]
    (js/console.log "A.constructor"))

  Object
  (whatever [this a b]
    (js/console.log "A.whatever" a b)
    (+ a b)))

(defclass B
  (extends A)

  (constructor [this]
    (super)
    (js/console.log "B.constructor"))

  Object
  (whatever [this a b]
    (js/console.log "B.whatever")
    ;; (.whatever super a b) super not declared
    (.whatever (js* "super") a b)))

(js/console.log (.whatever (B.) 1 2))

generates

demo.browser.A = class demo$browser$A {
    constructor() {
        var self__ = this;

        console.log("A.constructor");
    }
}
;
(demo.browser.A.prototype.whatever = (function(a, b) {
    var self__ = this;
    var this$ = this;
    console.log("A.whatever", a, b);

    return (a + b);
}
));
demo.browser.B = class demo$browser$B extends demo.browser.A {
    constructor() {
        super();
        var self__ = this;

        console.log("B.constructor");
    }
}
;
(demo.browser.B.prototype.whatever = (function(a, b) {
    var self__ = this;
    var this$ = this;
    console.log("B.whatever");

    return super.whatever(a, b);
}
));
console.log((new demo.browser.B()).whatever((1), (2)));

This should work but doesn't this super doesn't exist. Can't emulate it either via (js* "super") since the Object methods are just "attached" to the class via extend-type. Only the constructor is actually emitted as part of the class and the rest is then attached via B.prototype.whatever = function(...) { ... };, but the problem is that super is not available in that context, only directly in class methods.

A workarround is (.. A -prototype -whatever (call this a b)) but thats not great and emits an inference warning.

Should most likely lift Object method declarations out of the extend-type and directly into the class body. Will think about it for a bit.