marginalia icon indicating copy to clipboard operation
marginalia copied to clipboard

:extend-via-metadata in protocols breaks Marginalia

Open eigenhombre opened this issue 4 years ago • 3 comments

(ns broke.core
  (:require [marginalia.core :as m]))

(defprotocol Foo
  :extend-via-metadata true
  (baz [_] :foobaz))

(m/run-marginalia [])

this throws

2. Unhandled clojure.lang.Compiler$CompilerException
   Error compiling /tmp/broke/src/broke/core.clj at (8:1)
   #:clojure.error{:phase :compile-syntax-check,
                   :line 8,
                   :column 1,
                   :source "/tmp/broke/src/broke/core.clj"}
             Compiler.java: 7648  clojure.lang.Compiler/load
                      REPL:    1  broke.core/eval15444
                      REPL:    1  broke.core/eval15444
             Compiler.java: 7177  clojure.lang.Compiler/eval
             Compiler.java: 7132  clojure.lang.Compiler/eval
                  core.clj: 3214  clojure.core/eval
                  core.clj: 3210  clojure.core/eval
    interruptible_eval.clj:   82  nrepl.middleware.interruptible-eval/evaluate/fn/fn
                  AFn.java:  152  clojure.lang.AFn/applyToHelper
                  AFn.java:  144  clojure.lang.AFn/applyTo
                  core.clj:  665  clojure.core/apply
                  core.clj: 1973  clojure.core/with-bindings*
                  core.clj: 1973  clojure.core/with-bindings*
               RestFn.java:  425  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   82  nrepl.middleware.interruptible-eval/evaluate/fn
                  main.clj:  437  clojure.main/repl/read-eval-print/fn
                  main.clj:  437  clojure.main/repl/read-eval-print
                  main.clj:  458  clojure.main/repl/fn
                  main.clj:  458  clojure.main/repl
                  main.clj:  368  clojure.main/repl
               RestFn.java:  137  clojure.lang.RestFn/applyTo
                  core.clj:  665  clojure.core/apply
                  core.clj:  660  clojure.core/apply
                regrow.clj:   20  refactor-nrepl.ns.slam.hound.regrow/wrap-clojure-repl/fn
               RestFn.java: 1523  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   79  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:   56  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:  145  nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
                  AFn.java:   22  clojure.lang.AFn/run
               session.clj:  202  nrepl.middleware.session/session-exec/main-loop/fn
               session.clj:  201  nrepl.middleware.session/session-exec/main-loop
                  AFn.java:   22  clojure.lang.AFn/run
               Thread.java:  748  java.lang.Thread/run

1. Caused by java.lang.IllegalArgumentException
   Don't know how to create ISeq from: clojure.lang.Keyword

                   RT.java:  557  clojure.lang.RT/seqFrom
                   RT.java:  537  clojure.lang.RT/seq
                   RT.java:  723  clojure.lang.RT/more
                  core.clj:   73  clojure.core/rest
                  core.clj:   73  clojure.core/rest
                parser.clj:  238  marginalia.parser/extract-impl-docstring
                parser.clj:  236  marginalia.parser/extract-impl-docstring
                parser.clj:  242  marginalia.parser/extract-internal-docstrings/fn
                  core.clj: 2755  clojure.core/map/fn
              LazySeq.java:   42  clojure.lang.LazySeq/sval
              LazySeq.java:   51  clojure.lang.LazySeq/seq
                   RT.java:  535  clojure.lang.RT/seq
                  core.clj:  137  clojure.core/seq
                  core.clj:  660  clojure.core/apply
                  core.clj: 2783  clojure.core/mapcat
                  core.clj: 2783  clojure.core/mapcat
               RestFn.java:  423  clojure.lang.RestFn/invoke
                parser.clj:  242  marginalia.parser/extract-internal-docstrings
                parser.clj:  240  marginalia.parser/extract-internal-docstrings
                parser.clj:  250  marginalia.parser/eval13366/fn
              MultiFn.java:  239  clojure.lang.MultiFn/invoke
                parser.clj:  315  marginalia.parser/extract-docstring
                parser.clj:  312  marginalia.parser/extract-docstring
                parser.clj:  378  marginalia.parser/arrange-in-sections
                parser.clj:  337  marginalia.parser/arrange-in-sections
                parser.clj:  399  marginalia.parser/parse
                parser.clj:  387  marginalia.parser/parse
                parser.clj:  425  marginalia.parser/parse-file
                parser.clj:  422  marginalia.parser/parse-file
                  core.clj:  177  marginalia.core/path-to-doc
                  core.clj:  175  marginalia.core/path-to-doc
                  core.clj: 2753  clojure.core/map/fn
              LazySeq.java:   42  clojure.lang.LazySeq/sval
              LazySeq.java:   51  clojure.lang.LazySeq/seq
                   RT.java:  535  clojure.lang.RT/seq
                  core.clj:  137  clojure.core/seq
                  core.clj: 2746  clojure.core/map/fn
              LazySeq.java:   42  clojure.lang.LazySeq/sval
              LazySeq.java:   51  clojure.lang.LazySeq/seq
                   RT.java:  535  clojure.lang.RT/seq
                  core.clj:  137  clojure.core/seq
                  core.clj: 2746  clojure.core/map/fn
              LazySeq.java:   42  clojure.lang.LazySeq/sval
              LazySeq.java:   51  clojure.lang.LazySeq/seq
                   RT.java:  535  clojure.lang.RT/seq
                  core.clj:  137  clojure.core/seq
                  core.clj:  660  clojure.core/apply
                  core.clj:  660  clojure.core/apply
                hiccup.clj:   99  marginalia.hiccup/eval12872/fn
              MultiFn.java:  229  clojure.lang.MultiFn/invoke
                  Var.java:  384  clojure.lang.Var/invoke
                  html.clj:  198  marginalia.html/toc-html
                  html.clj:  197  marginalia.html/toc-html
                  html.clj:  409  marginalia.html/uberdoc-html
                  html.clj:  401  marginalia.html/uberdoc-html
                  core.clj:  206  marginalia.core/uberdoc!
                  core.clj:  196  marginalia.core/uberdoc!
                  core.clj:  311  marginalia.core/run-marginalia
                  core.clj:  248  marginalia.core/run-marginalia
               RestFn.java:  410  clojure.lang.RestFn/invoke
                  core.clj:    8  broke.core/eval15486
                  core.clj:    8  broke.core/eval15486
             Compiler.java: 7177  clojure.lang.Compiler/eval
             Compiler.java: 7636  clojure.lang.Compiler/load
                      REPL:    1  broke.core/eval15444
                      REPL:    1  broke.core/eval15444
             Compiler.java: 7177  clojure.lang.Compiler/eval
             Compiler.java: 7132  clojure.lang.Compiler/eval
                  core.clj: 3214  clojure.core/eval
                  core.clj: 3210  clojure.core/eval
    interruptible_eval.clj:   82  nrepl.middleware.interruptible-eval/evaluate/fn/fn
                  AFn.java:  152  clojure.lang.AFn/applyToHelper
                  AFn.java:  144  clojure.lang.AFn/applyTo
                  core.clj:  665  clojure.core/apply
                  core.clj: 1973  clojure.core/with-bindings*
                  core.clj: 1973  clojure.core/with-bindings*
               RestFn.java:  425  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   82  nrepl.middleware.interruptible-eval/evaluate/fn
                  main.clj:  437  clojure.main/repl/read-eval-print/fn
                  main.clj:  437  clojure.main/repl/read-eval-print
                  main.clj:  458  clojure.main/repl/fn
                  main.clj:  458  clojure.main/repl
                  main.clj:  368  clojure.main/repl
               RestFn.java:  137  clojure.lang.RestFn/applyTo
                  core.clj:  665  clojure.core/apply
                  core.clj:  660  clojure.core/apply
                regrow.clj:   20  refactor-nrepl.ns.slam.hound.regrow/wrap-clojure-repl/fn
               RestFn.java: 1523  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   79  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:   56  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:  145  nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
                  AFn.java:   22  clojure.lang.AFn/run
               session.clj:  202  nrepl.middleware.session/session-exec/main-loop/fn
               session.clj:  201  nrepl.middleware.session/session-exec/main-loop
                  AFn.java:   22  clojure.lang.AFn/run
               Thread.java:  748  java.lang.Thread/run

Without :extend-via-metadata (added in Clojure 1.10), it works fine.

eigenhombre avatar Feb 24 '21 21:02 eigenhombre

@eigenhombre Ever find a solution for this one? Just stumbled across it, and I'm hitting the same issue.

ALai57 avatar Oct 18 '22 21:10 ALai57

Seems like you can override the parser/dispatch-form multimethod for 'defprotocol, so maybe I'll do that and submit a PR

ALai57 avatar Oct 18 '22 21:10 ALai57

  (require '[marginalia.parser :as p])

;; Override the existing multimethod - proposal for a new multimethod that works with `:extend-via-metadata`
  (defmethod p/dispatch-form 'defprotocol
    [form raw nspace-sym]
    (let [[ds r s] (#'p/extract-common-docstring form raw nspace-sym)
          ewm      (contains? (set form) :extend-via-metadata)]
      (let [internal-dses (cond
                         ;; Sharp quotes because I was working outside of the parser ns, and the var is private
                            (and ewm ds) (#'p/extract-internal-docstrings (nthnext form 5))
                            ewm          (#'p/extract-internal-docstrings (nthnext form 4))
                            ds           (#'p/extract-internal-docstrings (nthnext form 3))
                            :else        (#'p/extract-internal-docstrings (nthnext form 2)))]
        (with-meta
          [ds r s]
          {:internal-docstrings internal-dses}))))

;; A test example proving it works
  (ns broke.core)

  (def broken-string
    "(defprotocol Foo
    \"Does a Foo\"
    :extend-via-metadata true
    (do-foo! [_ opts] \"Foo!\"))")

  (p/dispatch-form (read-string broken-string)
                   broken-string
                   'broke.core)
  ;; => ["Does a Foo"
  ;;     "(defprotocol Foo\n    :extend-via-metadata true\n    (do-foo! [_ opts] \"Foo!\"))"
  ;;     broke.core]

ALai57 avatar Oct 18 '22 21:10 ALai57