This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-08-20
Channels
- # announcements (1)
- # bangalore-clj (27)
- # beginners (82)
- # boot (4)
- # chestnut (1)
- # cider (22)
- # cljs-dev (26)
- # cljsrn (4)
- # clojure (118)
- # clojure-dev (18)
- # clojure-italy (2)
- # clojure-losangeles (1)
- # clojure-nl (2)
- # clojure-russia (1)
- # clojure-spec (15)
- # clojure-uk (125)
- # clojurescript (61)
- # core-async (74)
- # cursive (2)
- # datomic (41)
- # duct (6)
- # editors (7)
- # emacs (3)
- # events (1)
- # figwheel-main (3)
- # fulcro (111)
- # hoplon (11)
- # jobs-discuss (97)
- # lein-figwheel (99)
- # off-topic (34)
- # onyx (4)
- # parinfer (9)
- # pedestal (4)
- # precept (2)
- # re-frame (5)
- # reagent (2)
- # reitit (4)
- # ring-swagger (11)
- # shadow-cljs (104)
- # spacemacs (4)
- # tools-deps (19)
- # vim (8)
- # yada (15)
@dnolen Cool. Taking that as meaning you think https://dev.clojure.org/jira/browse/CLJS-2866 is worthwhile.
Pretty cool (predicate-induced inferrence):
(let [xxx 'a]
(inferred-type
(cond
(pos? xxx) xxx
(boolean? xxx) xxx
(nil? xxx) xxx
:else "foo")))
;=> #{boolean number string clj-nil}
A simpler one:
(let [xxx 'a] (inferred-type (if (double? xxx) xxx :kw)))
;=> #{cljs.core/Keyword number}
^ What you can’t really see is that the type inference goes with the then branch, so in that first example, only the xxx
on the pos?
branch is tagged with number
Proof of this assertion:
cljs.user=> (let [xxx 'a]
(cond
(string? xxx) (+ xxx 3)
(boolean? xxx) (+ xxx 3)))
WARNING: cljs.core/+, all arguments must be numbers, got [string number] instead at line 3 <cljs repl>
WARNING: cljs.core/+, all arguments must be numbers, got [boolean number] instead at line 4 <cljs repl>
nil
I have notice this differs from core: https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/spec/test/alpha.cljc#L231
the alias in core is clojure.spec.test.check
but then I checked the code and I am not sure where it is used...will see if I can patch it myself
uhm, never mind...seems like :clojure.test.check/opts
is handled correctly so all good
@mfikes a next step would be to type tagging predicates, i.e. seqable?
or instance?
, satisfies?
etc.
Yeah, I have single-arg predicates covered, I think, via this map here https://github.com/mfikes/clojurescript/commit/b1501165536709839281f2e2a4b6f8680d0e4559#diff-97c50fd669986fb95db3957c1bab83baR1444
instance?
and satisfies?
don’t fit into the pattern currently handled, but it seems like a mild extension to handle those cases
Oh, so, looking at the source for sequable?
, if would appear that in the then branch of
(if (seqable? x)
x
:foo)
the local x
should have the tag #{cljs.core/ISeqable array string}
. That could fit into the pattern easily. Just a sec…cljs.user=> (inferred-type (let [xxx 'x] (when (seqable? xxx) xxx)))
#{cljs.core/ISeqable array string clj-nil}
That was a trivial change. Got lucky. Just had to revise the predicate->tag
map to add an entry (I also added one for array?
)
(def ^:private predicate->tag
'{cljs.core/nil? clj-nil
cljs.core/boolean? boolean
cljs.core/string? string
cljs.core/number? number
cljs.core/double? number
cljs.core/integer? number
cljs.core/zero? number
cljs.core/pos? number
cljs.core/neg? number
cljs.core/seq? seq
cljs.core/array? array
cljs.core/seqable? #{cljs.core/ISeqable array string}})
I’d be interested in any information you compiled. It’s been a while since I’ve done cljs in vim and I’m curious about the composition of a working configuration.
Yeah ill write up a blogpost for it.
Cool, satisfies?
and instance?
appear to be easy to do:
cljs.user=> (inferred-type (let [xxx 'x] (if (satisfies? ICounted xxx) xxx 2)))
#{number cljs.core/ICounted}
cljs.user=> (inferred-type (let [xxx 'x] (if (instance? MapEntry xxx) xxx 2)))
#{cljs.core/MapEntry number}
but I think we’d have to add specific table entries for predicates like map-entry?
cljs.user=> (inferred-type (let [xxx 'x] (if (map-entry? xxx) xxx 2)))
#{number cljs.core/Symbol}
Will add the core predicates that delegate to satisfies?
and instance?
(like map-entry?
)I dropped a WIP patch in https://dev.clojure.org/jira/browse/CLJS-2866 for the above. It would actually probably be ready, apart from a unit test failure in cljs.extend-to-native-test
. But apart from that, the code is in good shape for any feedback.
The failure mode is interesting: In pr-writer-impl
we have a cond
branch that looks like
(satisfies? IPrintWithWriter obj)
(-pr-writer obj writer opts)
and here is what failure looks like
cljs.user=> (extend-type object
IPrintWithWriter
(-pr-writer [obj writer _]
(write-all writer "#object[custom-print-cljs-2812]")))
nil
cljs.user=> #js {}
repl:13
throw e__8737__auto__;
^
TypeError: obj.cljs$core$IPrintWithWriter$_pr_writer$arity$3 is not a function
at Object.cljs$core$pr_writer_impl [as pr_writer_impl] (/Users/mfikes/out/cljs/core.js:32916:12)
...
It appears that, since obj
gets tagged as being of type IPrintWithWriter
, the compiler appears to emit what looks like a static dispatch or somesuch to a method that doesn’t exist.
Revising the cond
branch to suppress this with ^any
, like this, fixes it:
(satisfies? IPrintWithWriter obj)
(-pr-writer ^any obj writer opts)
So this new tag information is provoking some sort of assumption in the compiler in this case.