<< Back to previous view

[MATCH-35] Bug in seq pattern matching Created: 27/Oct/11  Updated: 16/Jun/13  Resolved: 16/Jun/13

Status: Resolved
Project: core.match
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Critical
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   
(let [l '(1 2 3)]
    (match [l]
      [([a & [b & [c d]]] :seq)] :a0
      :else :a1))

Matches when it shouldn't.



 Comments   
Comment by Greg Chapman [ 11/Jan/12 10:24 AM ]

Another example of (I think) the same issue:

user=> (let [x ()] (match [x] [([h & t] :seq)] [h t] [_] :a1))
[nil ()]

Perhaps SeqPattern's IPatternCompile should call seq in order to filter empty seqs? (e.g.:

(to-source* [this ocr]
`(and (or (seq? ~ocr) (sequential? ~ocr)) (seq ~ocr)))

Comment by David Nolen [ 16/Jun/13 10:38 PM ]

fixed, http://github.com/clojure/core.match/commit/37564e32d34547e7d8a71f7abc631cce9585dd4e





[MATCH-47] vector patterns dispatch on count after dispatching on type Created: 23/Dec/11  Updated: 16/Jun/13  Resolved: 16/Jun/13

Status: Resolved
Project: core.match
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Critical
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

The current behavior just creates complications.



 Comments   
Comment by David Nolen [ 16/Jun/13 10:22 PM ]

as of http://github.com/clojure/core.match/commit/59df5b32b3c06b0038f76ccb88670fa9f42e5547 we always check size when applicable





[MATCH-68] Vector match "underflow" => IndexOutOfBoundsException Created: 22/Apr/13  Updated: 16/Jun/13  Resolved: 16/Jun/13

Status: Resolved
Project: core.match
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Chas Emerick Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File vector-rest-WIP.diff    
Patch: Code and Test

 Description   

This fails with 0.2.0-alpha12:

(match [[:x]]
  [[m n & _]] 1)

I expect nil, but an unguarded subvec call throws an IndexOutOfBoundsException.

A WIP patch is attached that fixes this (perhaps incorrectly) but which produced regressions (outside of core.match), e.g.

(match [[[:x "t"]]]
 [[[:x & a] & tail]] :a
 [[[:y & p] [:x & a] & tail]] :b)
=> nil

The patch also "fixes" this (by changing pattern-compare behaviour for rest VectorPattern s, but that leads to a regression in the vector-pattern-rest-2 testcase in core.match.

(Original discussion with further background here.)



 Comments   
Comment by Greg Chapman [ 24/Apr/13 5:26 PM ]

FWIW, I've been using the patch described here, and haven't yet run into any problems, though I also haven't used core.match that much. Anyway, with the change to subvec-inline, both of the cases here act as expected (producing nil and :a, respectively).

(I note looking at my patch that I'm doubly-evaluating ocr in the second overload; obviously that should be fixed with a let binding).

Comment by David Nolen [ 18/May/13 3:11 PM ]

The patch looks like it's going in the right direction. Can you explain why your patch without the pattern-compares case causes the second example to fail?

Comment by David Nolen [ 16/Jun/13 10:10 PM ]

fixed, http://github.com/clojure/core.match/commit/302c355ebf751fa8dc442c8db8b901ebb4eacfae





[MATCH-56] IndexOutOfBoundsException when matching empty vector Created: 27/Mar/12  Updated: 16/Jun/13  Resolved: 16/Jun/13

Status: Resolved
Project: core.match
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Greg Chapman Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None
Environment:

Clojure 1.3


Attachments: File match.clj.diff    

 Description   

Using the latest core.match:

user=> (let [x []] (match [x] [[h & t]] [h t] :else :nomatch))
IndexOutOfBoundsException   clojure.lang.RT.subvec (RT.java:1451)

Not sure if this is the best fix, but I resolved this specific case by slightly changing subvec-inline (see attached diff).



 Comments   
Comment by David Nolen [ 27/Mar/12 10:28 AM ]

Thanks for the report. The patch is not going to work - we should be checking that the vector has at least one item.

Comment by David Nolen [ 16/Jun/13 10:08 PM ]

fixed http://github.com/clojure/core.match/commit/59df5b32b3c06b0038f76ccb88670fa9f42e5547





[MATCH-69] AOT-compiling match expression produces stack overflow Created: 24/Apr/13  Updated: 16/Jun/13  Resolved: 16/Jun/13

Status: Closed
Project: core.match
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Chas Emerick Assignee: Chas Emerick
Resolution: Declined Votes: 0
Labels: None


 Description   

The offending match expression is pretty gnarly, will try to simplify and post it here later. For now, a (partial) stack trace, eliding the repeating bits:

Caused by: java.lang.StackOverflowError
	at clojure.core$map$fn__4207.invoke(core.clj:2479)
	at clojure.lang.LazySeq.sval(LazySeq.java:42)
	at clojure.lang.LazySeq.seq(LazySeq.java:60)
	at clojure.lang.ChunkedCons.chunkedNext(ChunkedCons.java:59)
	at clojure.lang.ChunkedCons.next(ChunkedCons.java:43)
	at clojure.lang.PersistentVector.create(PersistentVector.java:51)
	at clojure.lang.LazilyPersistentVector.create(LazilyPersistentVector.java:31)
	at clojure.core$vec.invoke(core.clj:354)
	at clojure.core.match.PatternMatrix.column(match.clj:713)
	at clojure.core.match$useful_p_QMARK_.invoke(match.clj:811)
	at clojure.core.match.PatternMatrix$iter__1458__1464$fn__1465$iter__1460__1466$fn__1467$fn__1468.invoke(match.clj:765)
	at clojure.core.match.PatternMatrix$iter__1458__1464$fn__1465$iter__1460__1466$fn__1467.invoke(match.clj:763)
	at clojure.lang.LazySeq.sval(LazySeq.java:42)
	at clojure.lang.LazySeq.seq(LazySeq.java:60)
	at clojure.lang.RT.seq(RT.java:484)
	at clojure.core$seq.invoke(core.clj:133)
	at clojure.core.match.PatternMatrix$iter__1458__1464$fn__1465.invoke(match.clj:764)
	at clojure.lang.LazySeq.sval(LazySeq.java:42)
	at clojure.lang.LazySeq.seq(LazySeq.java:67)
	at clojure.lang.RT.seq(RT.java:484)
	at clojure.core$seq.invoke(core.clj:133)
	at clojure.core$partition$fn__4309.invoke(core.clj:2834)
	at clojure.lang.LazySeq.sval(LazySeq.java:42)
	at clojure.lang.LazySeq.seq(LazySeq.java:60)
	at clojure.lang.RT.seq(RT.java:484)
	at clojure.core$seq.invoke(core.clj:133)
	at clojure.core$map$fn__4207.invoke(core.clj:2479)
	at clojure.lang.LazySeq.sval(LazySeq.java:42)
	at clojure.lang.LazySeq.seq(LazySeq.java:60)
	at clojure.lang.Cons.next(Cons.java:39)
	at clojure.lang.PersistentVector.create(PersistentVector.java:51)
	at clojure.lang.LazilyPersistentVector.create(LazilyPersistentVector.java:31)
	at clojure.core$vec.invoke(core.clj:354)
	at clojure.core.match.PatternMatrix.useful_matrix(match.clj:763)
	at clojure.core.match.PatternMatrix.necessary_column(match.clj:755)
	at clojure.core.match.PatternMatrix$choose_column__1441.invoke(match.clj:720)
	at clojure.core.match.PatternMatrix.compile(match.clj:738)
	at clojure.core.match$first_column_chosen_case$switch_clauses__1406$fn__1407.invoke(match.clj:643)
	at clojure.core$map$fn__4211.invoke(core.clj:2492)
	at clojure.lang.LazySeq.sval(LazySeq.java:42)
	at clojure.lang.LazySeq.seq(LazySeq.java:60)
	at clojure.lang.RT.seq(RT.java:484)
	at clojure.core$seq.invoke(core.clj:133)
	at clojure.core.protocols$seq_reduce.invoke(protocols.clj:30)
	at clojure.core.protocols$fn__6026.invoke(protocols.clj:54)
	at clojure.core.protocols$fn__5979$G__5974__5992.invoke(protocols.clj:13)
	at clojure.core$reduce.invoke(core.clj:6177)
	at clojure.core$into.invoke(core.clj:6229)
	at clojure.core.match$first_column_chosen_case$switch_clauses__1406.invoke(match.clj:646)
	at clojure.core.match$first_column_chosen_case.invoke(match.clj:676)
	at clojure.core.match.PatternMatrix.compile(match.clj:740)
	at clojure.core.match$first_column_chosen_case$switch_clauses__1406$fn__1407.invoke(match.clj:643)
	at clojure.core$map$fn__4211.invoke(core.clj:2492)
	at clojure.lang.LazySeq.sval(LazySeq.java:42)
	at clojure.lang.LazySeq.seq(LazySeq.java:60)
	at clojure.lang.RT.seq(RT.java:484)
	at clojure.core$seq.invoke(core.clj:133)
	at clojure.core.protocols$seq_reduce.invoke(protocols.clj:30)
	at clojure.core.protocols$fn__6026.invoke(protocols.clj:54)
	at clojure.core.protocols$fn__5979$G__5974__5992.invoke(protocols.clj:13)
	at clojure.core$reduce.invoke(core.clj:6177)
	at clojure.core$into.invoke(core.clj:6229)


 Comments   
Comment by David Nolen [ 02/Jun/13 11:39 AM ]

As it is this ticket is not useful. Chas can you add the minimal case? Thanks!

Comment by David Nolen [ 15/Jun/13 10:37 PM ]

Without more details I'm inclined closed to this. I just need a minimal case and will be happy to investigate.

Comment by Chas Emerick [ 16/Jun/13 4:47 PM ]

I never was able to get a sane minimal case together. Later, I just coded around the problem, and all of the changes on master may make the issue moot at this point anyway. Closing.





[MATCH-55] Matching a sequence with just a rest pattern fails to compile Created: 21/Mar/12  Updated: 16/Jun/13  Resolved: 16/Jun/13

Status: Resolved
Project: core.match
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Hugo Duncan Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

In 0.2.0-alpha9,

(match [ [1 2] ] [([& _] :seq)] true)

fails to compile with No method in multimethod 'to-source' for dispatch value: class clojure.core.match.RestPattern



 Comments   
Comment by David Nolen [ 16/Jun/13 4:13 PM ]

fixed, http://github.com/clojure/core.match/commit/d09ef3bf3d4264aee0c6da5436b760a996811e17





[MATCH-2] Matching Diagnostics Created: 04/Sep/11  Updated: 16/Jun/13

Status: Open
Project: core.match
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: David Nolen Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Communicate to the user precisely what failed to match. Conversation here: http://groups.google.com/group/clojure/browse_thread/thread/675456fba1712214. We adopt the behavior of condp since that is closer to what match does and will do (predicate dispatch)



 Comments   
Comment by David Nolen [ 05/Sep/11 10:40 AM ]

Continuing the conversation from GitHub - concerning your changes, we should probably show what current occurrence failed to match as well as the breadcrumb.

Comment by David Nolen [ 26/Sep/11 7:10 AM ]

Matching diagnostics will be complicated by MATCH-1. Clojure doesn't yet support simple data conveying exceptions. Will probably have to use a combination of proxy and definterface.

Comment by Ambrose Bonnaire-Sergeant [ 30/Sep/11 4:39 AM ]

I haven't yet kept up with your backtracking changes, and I just noticed this conversation, so I'll have to have another look at diagnostics with backtracking.

Comment by David Nolen [ 16/Jun/13 1:57 PM ]

Lowering priority. Happy to take a patch, but I don't think I'll be looking into this myself in the near future.





[MATCH-63] IllegalArgumentException when AOT compiling namespace using clojure.core.match since alpha10 Created: 08/Aug/12  Updated: 15/Jun/13  Resolved: 15/Jun/13

Status: Resolved
Project: core.match
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Paudi Moriarty Assignee: David Nolen
Resolution: Completed Votes: 3
Labels: None
Environment:

core.match 0.2.0-alpha10 and 0.2.0-alpha11-SNAPSHOT (git 7ad66cc)
clojure 1.3.0 and 1.4.0


Attachments: Zip Archive matchtest.zip    

 Description   

Getting this when AOT compiling a trivial project (attached) using alpha10: (works fine with alpha9)

Caused by: java.lang.IllegalArgumentException: No method in multimethod 'to-source' for dispatch value: class clojure.core.match.WildcardPattern
	at clojure.lang.MultiFn.getFn(MultiFn.java:121)
	at clojure.lang.MultiFn.invoke(MultiFn.java:167)
	at clojure.core.match$dag_clause_to_clj.invoke(match.clj:424)
	at clojure.lang.AFn.applyToHelper(AFn.java:167)
	at clojure.lang.AFn.applyTo(AFn.java:151)
	at clojure.core$apply.invoke(core.clj:602)
	at clojure.lang.AFn.applyToHelper(AFn.java:167)
	at clojure.lang.RestFn.applyTo(RestFn.java:132)
	at clojure.core$apply.invoke(core.clj:604)
	at clojure.core$partial$fn__3796.doInvoke(core.clj:2343)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$map$fn__3811.invoke(core.clj:2430)
	at clojure.lang.LazySeq.sval(LazySeq.java:42)
	at clojure.lang.LazySeq.seq(LazySeq.java:60)
	at clojure.lang.RT.seq(RT.java:466)
	at clojure.core$seq.invoke(core.clj:133)
	at clojure.core$apply.invoke(core.clj:600)
	at clojure.core$mapcat.doInvoke(core.clj:2459)
	at clojure.lang.RestFn.invoke(RestFn.java:423)
	at clojure.core.match.SwitchNode.n_to_clj(match.clj:446)
	at clojure.core.match.BindNode.n_to_clj(match.clj:411)
	at clojure.core.match$executable_form.invoke(match.clj:1713)
	at clojure.core.match$clj_form.invoke(match.clj:1721)
	at clojure.core.match$match.doInvoke(match.clj:1750)


 Comments   
Comment by Frederik De Bleser [ 20/Nov/12 4:18 PM ]

I can confirm the same issue on alpha11.

Comment by David Nolen [ 23/Nov/12 4:52 PM ]

I believe I may have found the cause and have fixed master - if someone can confirm I'll happily cut another release.

http://github.com/clojure/core.match/commit/cbcc6e5fa070a7025e72f5eab4e83eaec100332b

Comment by Paudi Moriarty [ 15/Jan/13 9:42 AM ]

Thanks David,

That change has not fixed the issue for me.

Comment by Paudi Moriarty [ 15/Jan/13 9:56 AM ]

So the pattern parameter being passed to dag-clause-to-clj:

(defn dag-clause-to-clj [occurrence pattern action]
  (let [test (if (instance? clojure.core.match.IPatternCompile pattern)
               (to-source* pattern occurrence)
               (to-source pattern occurrence))]
...

is a WildcardPattern which doesn't implement IPatternCompile and doesn't have a to-source method. So it seems it shouldn't be passed at all. Indeed, in normal usage it isn't.

;; ## Wildcard Pattern
;; 
;; A wildcard pattern accepts any value.
;;
;; In practice, the DAG compilation eliminates any wildcard patterns.

(defprotocol IWildcardPattern
  (sym [this]))

(deftype WildcardPattern [sym _meta]
  IWildcardPattern
  (sym [_] sym)
  clojure.lang.IObj
  (meta [_] _meta)
  (withMeta [_ new-meta]
    (WildcardPattern. sym new-meta))
  Object
  (toString [_]
    (str sym)))
Comment by David Nolen [ 15/Jan/13 11:17 AM ]

Can you include an example pattern which works under normal circumstances but fails under AOT? This must meant that WildcardPatterns are making it through under AOT and getting to the multimethod case but not under incremental compilation at the REPL.

Comment by Paudi Moriarty [ 16/Jan/13 9:34 AM ]

This seems to do it:

(match {}
  {:a :x :b b} :dummy
  :else :dummy)
Comment by Tim Olsen [ 26/Feb/13 1:55 PM ]

I've seen this problem as well. If I try to compile a second time, however, without running lein clean, the compilation succeeds. Maybe it's a bootstrapping problem?

Comment by David Nolen [ 15/Jun/13 10:38 PM ]

as far as I can tell, this is the same issue as MATCH-53 which is resolved in master. Unless I hear otherwise, I'm closing this one.





[MATCH-65] cata matching Created: 23/Nov/12  Updated: 15/Jun/13

Status: Open
Project: core.match
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: David Nolen Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Dan Friedman's pattern matcher has a nice feature called cata-matching - allowing recursive matching from the match itself. Useful when writing compilers.






[MATCH-54] Cannot AOT with certain match expression. Created: 04/Mar/12  Updated: 15/Jun/13  Resolved: 15/Jun/13

Status: Resolved
Project: core.match
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Jason Jackson Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

If you try to AOT this code, you get an exception.

(defn -main [& args]
  (println args)
  (let [x nil] 
    (match x
      ["=" _ _] true
      [[:invoke _] _] true)))

Stack Trace:

Compiling foo.core
Exception in thread "main" java.lang.IndexOutOfBoundsException, compiling:(foo/core.clj:8)
	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6416)
	at clojure.lang.Compiler.analyze(Compiler.java:6216)
	at clojure.lang.Compiler.analyze(Compiler.java:6177)
	at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5572)
	at clojure.lang.Compiler$LetExpr$Parser.parse(Compiler.java:5873)
	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6409)
	at clojure.lang.Compiler.analyze(Compiler.java:6216)
	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6397)
	at clojure.lang.Compiler.analyze(Compiler.java:6216)
	at clojure.lang.Compiler.analyze(Compiler.java:6177)
	at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5572)
	at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5008)
	at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3629)
	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6407)
	at clojure.lang.Compiler.analyze(Compiler.java:6216)
	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6397)
	at clojure.lang.Compiler.analyze(Compiler.java:6216)
	at clojure.lang.Compiler.access$100(Compiler.java:37)
	at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:492)
	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6409)
	at clojure.lang.Compiler.analyze(Compiler.java:6216)
	at clojure.lang.Compiler.analyze(Compiler.java:6177)
	at clojure.lang.Compiler.compile1(Compiler.java:6980)
	at clojure.lang.Compiler.compile(Compiler.java:7046)
	at clojure.lang.RT.compile(RT.java:385)
	at clojure.lang.RT.load(RT.java:425)
	at clojure.lang.RT.load(RT.java:398)
	at clojure.core$load$fn__4610.invoke(core.clj:5386)
	at clojure.core$load.doInvoke(core.clj:5385)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invoke(core.clj:5200)
	at clojure.core$compile$fn__4615.invoke(core.clj:5397)
	at clojure.core$compile.invoke(core.clj:5396)
	at user$eval27.invoke(NO_SOURCE_FILE:1)
	at clojure.lang.Compiler.eval(Compiler.java:6465)
	at clojure.lang.Compiler.eval(Compiler.java:6455)
	at clojure.lang.Compiler.eval(Compiler.java:6431)
	at clojure.core$eval.invoke(core.clj:2795)
	at clojure.main$eval_opt.invoke(main.clj:296)
	at clojure.main$initialize.invoke(main.clj:315)
	at clojure.main$null_opt.invoke(main.clj:348)
	at clojure.main$main.doInvoke(main.clj:426)
	at clojure.lang.RestFn.invoke(RestFn.java:421)
	at clojure.lang.Var.invoke(Var.java:405)
	at clojure.lang.AFn.applyToHelper(AFn.java:163)
	at clojure.lang.Var.applyTo(Var.java:518)
	at clojure.main.main(main.java:37)
Caused by: java.lang.IndexOutOfBoundsException
	at clojure.lang.PersistentVector.arrayFor(PersistentVector.java:106)
	at clojure.lang.PersistentVector.nth(PersistentVector.java:110)
	at clojure.lang.RT.nth(RT.java:741)
	at clojure.core.match.PatternRow.invoke(match.clj:327)
	at clojure.core.match.PatternMatrix.pattern_at(match.clj:713)
	at clojure.core.match$useful_p_QMARK_.invoke(match.clj:778)
	at clojure.core.match.PatternMatrix$iter__832__838$fn__839$iter__834__840$fn__841$fn__842.invoke(match.clj:735)
	at clojure.core.match.PatternMatrix$iter__832__838$fn__839$iter__834__840$fn__841.invoke(match.clj:733)
	at clojure.lang.LazySeq.sval(LazySeq.java:42)
	at clojure.lang.LazySeq.seq(LazySeq.java:60)
	at clojure.lang.RT.seq(RT.java:466)
	at clojure.core$seq.invoke(core.clj:133)
	at clojure.core.match.PatternMatrix$iter__832__838$fn__839.invoke(match.clj:734)
	at clojure.lang.LazySeq.sval(LazySeq.java:42)
	at clojure.lang.LazySeq.seq(LazySeq.java:67)
	at clojure.lang.RT.seq(RT.java:466)
	at clojure.core$seq.invoke(core.clj:133)
	at clojure.core$partition$fn__3913.invoke(core.clj:2777)
	at clojure.lang.LazySeq.sval(LazySeq.java:42)
	at clojure.lang.LazySeq.seq(LazySeq.java:60)
	at clojure.lang.RT.seq(RT.java:466)
	at clojure.core$seq.invoke(core.clj:133)
	at clojure.core$map$fn__3811.invoke(core.clj:2424)
	at clojure.lang.LazySeq.sval(LazySeq.java:42)
	at clojure.lang.LazySeq.seq(LazySeq.java:60)
	at clojure.lang.Cons.next(Cons.java:39)
	at clojure.lang.PersistentVector.create(PersistentVector.java:50)
	at clojure.lang.LazilyPersistentVector.create(LazilyPersistentVector.java:31)
	at clojure.core$vec.invoke(core.clj:345)
	at clojure.core.match.PatternMatrix.useful_matrix(match.clj:733)
	at clojure.core.match.PatternMatrix.necessary_column(match.clj:725)
	at clojure.core.match.PatternMatrix$choose_column__815.invoke(match.clj:690)
	at clojure.core.match.PatternMatrix.compile(match.clj:708)
	at clojure.core.match$first_column_chosen_case$switch_clauses__780$fn__781.invoke(match.clj:613)
	at clojure.core$map$fn__3815.invoke(core.clj:2437)
	at clojure.lang.LazySeq.sval(LazySeq.java:42)
	at clojure.lang.LazySeq.seq(LazySeq.java:60)
	at clojure.lang.RT.seq(RT.java:466)
	at clojure.core$seq.invoke(core.clj:133)
	at clojure.core$reduce.invoke(core.clj:5994)
	at clojure.core$into.invoke(core.clj:6004)
	at clojure.core.match$first_column_chosen_case$switch_clauses__780.invoke(match.clj:616)
	at clojure.core.match$first_column_chosen_case.invoke(match.clj:646)
	at clojure.core.match.PatternMatrix.compile(match.clj:710)
	at clojure.core.match$first_column_chosen_case$switch_clauses__780$fn__781.invoke(match.clj:613)
	at clojure.core$map$fn__3815.invoke(core.clj:2437)
	at clojure.lang.LazySeq.sval(LazySeq.java:42)
	at clojure.lang.LazySeq.seq(LazySeq.java:60)
	at clojure.lang.RT.seq(RT.java:466)
	at clojure.core$seq.invoke(core.clj:133)
	at clojure.core$reduce.invoke(core.clj:5994)
	at clojure.core$into.invoke(core.clj:6004)
	at clojure.core.match$first_column_chosen_case$switch_clauses__780.invoke(match.clj:616)
	at clojure.core.match$first_column_chosen_case.invoke(match.clj:646)
	at clojure.core.match.PatternMatrix.compile(match.clj:710)
	at clojure.core.match$clj_form.invoke(match.clj:1616)
	at clojure.core.match$match.doInvoke(match.clj:1645)
	at clojure.lang.RestFn.invoke(RestFn.java:573)
	at clojure.lang.Var.invoke(Var.java:426)
	at clojure.lang.AFn.applyToHelper(AFn.java:193)
	at clojure.lang.Var.applyTo(Var.java:518)
	at clojure.lang.Compiler.macroexpand1(Compiler.java:6320)
	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6395)
	... 46 more


 Comments   
Comment by David Nolen [ 15/Jun/13 10:33 PM ]

as far as I can tell this AOT bug is resolved in master





[MATCH-70] Matches against maps are treated as wildcards, even though they are not Created: 29/May/13  Updated: 15/Jun/13  Resolved: 15/Jun/13

Status: Resolved
Project: core.match
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Pollak Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File 0001-Fixed-the-map-wildcard-issue.patch    
Patch: Fixed

 Description   

The following tests fail:

(deftest map-pattern-match-bind-2
  (is (= (let [xqq {:cz 1 :dz 2}]
           (match [xqq]
             [{:z a :zz b}] [:a0 a b]
             [{:cz a :dz b}] [:a2 a b]
             :else []))
        [:a2 1 2])))

(deftest map-pattern-match-bind-3
  (is (= (let [xmm {:bz 2}]
           (match [xmm]
             [{:az a}] [:a0 a]
             [{:bz b}] [:a1 b]
             :else []))
        [:a1 2])))


 Comments   
Comment by David Nolen [ 29/May/13 8:26 PM ]

Thanks for the patch but this won't work - this defeats sharing tests. I'm looking into it.

Comment by David Pollak [ 29/May/13 10:38 PM ]

Thanks David. I was thinking about putting a "is this really a wildcard" flag on Wildcard and set it to false for Wildcards in MapPattern.

Anyway... if you want me to keep working on the issue, I'll be glad to. If my clumsy code and clumsy approach doesn't help... I'm down for sitting on the sidelines and watching you do the work.

Comment by David Nolen [ 30/May/13 12:35 AM ]

The issue is a bit trickier than it seems. core.match is written in a way such that we always try to share tests across patterns as much as possible. For example consider what happens with map patterns:

(match [x]
  [{:a _ :b 1}] ...
  [{:b _ :c 2}] ...)

In order to do optimal test sharing we expand the above into the following more or less (which is wrong):

:a :b :c
[_  1  _]
[_  _  2]

The problem here is that only the last element in the first row and the first element of the second row are true wildcards. Currently as you discovered the analysis doesn't consider the fact that the other wildcards really must be tested. So really we want something like the following:

:a    :b    :c
[V(_)  1     _]
[_     V(_)  2]

Here you can see we wrap the wildcard in a new pattern type - MapValuePattern. This will prevent the bad analysis.

I hope this makes sense - I've started implementing this and I don't think it will take me too long.

Just to make it a bit more clear imagine the following:

(match [x]
  [{:a _ :b _}] ...
  [{:b _ :c _}] ...)
:a    :b    :c
[V(_)  V(_)  _   ]
[_     V(_)  V(_)]

The wrapping now prevents the first row from being considered a row of wildcards.

Comment by David Nolen [ 02/Jun/13 11:33 AM ]

This should be fixed in master as of this commit http://github.com/clojure/core.match/commit/a07c2e9620df5b9d331bd6c380d47c15bf7cd60d

Let me know if it works for you.

Comment by David Pollak [ 02/Jun/13 1:00 PM ]

Awesome. Thanks! Please let me know when there are new JAR files in clojars.

Comment by David Nolen [ 15/Jun/13 10:30 PM ]

this has been resolved http://github.com/clojure/core.match/commit/a07c2e9620df5b9d331bd6c380d47c15bf7cd60d





[MATCH-57] Non deterministic match behavior for seqs when AOT Created: 05/Apr/12  Updated: 15/Jun/13  Resolved: 15/Jun/13

Status: Resolved
Project: core.match
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Ronen Narkis Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None
Environment:

Clojure 1.3

Leiningen 1.7.1 on Java 1.6.0_26

core.match "0.2.0-alpha9"



 Description   

The following source example:

https://github.com/narkisr/match-issue/blob/master/src/match_issue/core.clj

The defrule macro calls a function called lhs that use the match library,

this function calls it self recursively and print out the rest of body left to be matched,

When running lein compile two different results appear (in non deterministic fashion):

(when $message :> Message (== level 6) :from (entry-point event-stream))
($message :> Message (== level 6) :from (entry-point event-stream))
(Message (== level 6) :from (entry-point event-stream))
((== level 6) :from (entry-point event-stream))

This is the bug, as (== level 6) should be matched by:

[([([(o :when operator?) f s] :seq) :as c & r] :seq)]

In other cases the output is (the correct one):

(when $message :> Message (== level 6) :from (entry-point event-stream))
($message :> Message (== level 6) :from (entry-point event-stream))
(Message (== level 6) :from (entry-point event-stream))
((== level 6) :from (entry-point event-stream))
(:from (entry-point event-stream))
(entry-point event-stream)
()
()



 Comments   
Comment by David Nolen [ 06/Apr/12 11:03 AM ]

All AOT related issues w/o patches are low priority for the foreseeable future. They are simply too time consuming to track down and I don't have the bandwidth at the moment. I will get to them eventually, but if you want movement on this please submit a patch. I will happily apply it!

Comment by Ronen Narkis [ 07/Apr/12 7:53 PM ]

Hey David,

After going through the source code and some more in depth look I managed to understand what was going on, first iv stepped through the different stages

(def m (emit-matrix ['body]
'( [(['when & r] :seq)] (lhs r)
[(['accumulate & r] :seq)] (<< "accumulate(~(lhs r))")
[([bind ':> & r] :seq)] (<< "~{bind}:~(lhs r)"); pattern with bind
[([(t :when is-type?) & r] :seq)] (<< "{t}(lhs r)"); pattern
[([([(f :when acc-fn?) & args] :seq) & r] :seq)] (<< ",{f}{args}~(lhs r)" ); accumulate function
[([':from dest & r] :seq)] (<< "from ~(lhs dest) ~(lhs r)")
[([':over win & r] :seq)] (<< "over ~(window win) ~(lhs r)")
[([([(o :when operator?) f s] :seq) :as c & r] :seq)] (<< "(~(reduce str (map pr-str (to-infix c)))) ~(lhs r)")
[(['entry-point point & r] :seq)] (<< "entry-point \"~{point}\"~(lhs r)")
:else ""
)))

(def c (cm/compile m))

(pprint c)

(pprint (executable-form c))

The last pprint failed aot compilation:

$ lein compile

...
Caused by: java.lang.ClassCastException: clojure.core.match.WildcardPattern cannot be cast to java.lang.String

Which was very weird as I could clearly see that:

(deftype WildcardPattern [sym _meta]
IWildcardPattern
(sym [_] sym)
clojure.lang.IObj
(meta [_] _meta)
(withMeta [_ new-meta]
(WildcardPattern. sym new-meta))
Object
(toString [_]
(str sym)))

Then iv also tried to enabled trace:

(set-trace! true)

Which resulted with:

$ lein compile

...

TRACE: DAG: Column 0 : [#<SeqPattern #<LiteralPattern window> #<LiteralPattern :time> #<WildcardPattern t> #<WildcardPattern unit>>]
TRA at clojure.lang.Compiler.analyzeSeq(Compiler.java:6416)
at clojure.lang.Compiler.analyze(Compiler.java:6216)
at clojure.lang.Compiler.analyze(Compiler.java:6177)
at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5572)
at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5008)
at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3629)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6407)
at clojure.lang.Compiler.analyze(Compiler.java:6216)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6397)
at clojure.lang.Compiler.analyze(Compiler.java:6216)
at clojure.lang.Compiler.access$100(Compiler.java:37)
at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:492)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6409)
at clojure.lang.Compiler.analyze(Compiler.java:6216)
at clojure.lang.Compiler.analyze(Compiler.java:6177)
at clojure.lang.Compiler.compile1(Compiler.java:6980)
at clojure.lang.Compiler.compile(Compiler.java:7046)
at clojure.lang.RT.compile(RTCE: DAG: Add switch-node on occurrence exp

The most weird thing was that on second compile it all went well, this raised a flag and my suspicion was that the core.match classes got compiled on the first run:

$ ls classes/

match$analyze_actions$analyze_action__1166.class
match$analyze_actions.class
match$backtrack_expr.class
match$bind_node.class
match$catch_error.class
match$check_matrix_args$check_pattern__1150.class
...

Then iv decided to AOT compile clojure.core match:

$ git checkout core.match-0.2.0-alpha9
$ git diff project.clj
-(defproject match "0.2.0-alpha10-SNAPSHOT"
+(defproject match "0.2.0-alpha10-aot"
:description "Optimized pattern matching and predicate dispatch for Clojure"
:source-path "src/main/clojure"

  • :test-path "src/test/clojure")
    + :test-path "src/test/clojure"
    + :aot [clojure.core.match]
    + )

After using the aot jar it all went smooth including passing my non deterministic case (which is deterministic but very confusing to track down),

In order to reproduce it its important to run:

$ lein clean
$ rm -rf lib

And only then run

$ lein compile

Otherwise the classes dir might contain AOT'ed classes and make it seem that even non-aot jar works fine (its enough to run lein compile once to cause the classes to get compiled),

The fix in my case is simple, just AOT ns.

Im not sure if this Is a bug in the way Clojure AOT its classes but I think that adding the AOT'ed classes to the default core match distro is a reasonable workaround

BTW when using master (and not the tag) iv stumbled upon:

Exception in thread "main" java.lang.AssertionError: Assert failed: Unknown predicate in [is-type?]

Which is a pred defined in my ns.

Comment by David Nolen [ 15/Jun/13 10:30 PM ]

This sounds very similar to the other AOT bug reported by Kevin Lynagh MATCH-53 which is fixed in master, unless I hear different this is resolved.





[MATCH-36] throw on unsuccessful match Created: 27/Oct/11  Updated: 15/Jun/13  Resolved: 15/Jun/13

Status: Resolved
Project: core.match
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Critical
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 1
Labels: None


 Description   

I was on the fence about this. But after looking at the literature as well as the behavior of condp, I've decided that throwing on unsuccessful match is the way to go. This is particularly important since we put no constraints on the types allowed - we cannot determine exhaustiveness.



 Comments   
Comment by David Pollak [ 28/May/13 10:20 AM ]

FWIW, I think the existing behavior (returning a nil) is the correct behavior. If a user wants to throw an exception, they can add an :else clause.

Why is the existing behavior correct?

Think of a Map as a match. When you look up a key that is not in the Map, you get a nil. There are simple ways to add additional behavior to maps to return something other than a nil, but the default is nil.

A Map, like a pattern match, is defined at some values of the input and not other values of the input.

Comment by David Nolen [ 28/May/13 10:26 AM ]

The behavior aligns with Clojure's case. The issue is that Clojure being dynamically typed (and match actively taking advantage of this) can't really do exhaustiveness checking in all cases - I think throwing is desirable, and experience seems to suggest this as well - otherwise nils will flow in likely unintentional ways. Users can always add the explicit nil return if they like. I suspect users will not do this.

Comment by David Nolen [ 15/Jun/13 10:27 PM ]

fixed, http://github.com/clojure/core.match/commit/63e56f524e60644460a9e43e1312966c42c3a5d5





[MATCH-64] Improve match compile times Created: 15/Aug/12  Updated: 15/Jun/13

Status: Open
Project: core.match
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: David Nolen Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None





[MATCH-61] Exception thrown when matching using :seq when there is a seq call in the tail of the occurrences Created: 22/Jun/12  Updated: 15/Jun/13

Status: Open
Project: core.match
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Emma Tosch Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: bug, seq
Environment:

with Clojure 1.3



 Description   

The following match throws:

(let [q '(a) y '(b) z '(c)]
(match [q (seq y) z]
  [([_] :seq) _ _] 'a
  [_ _ _] 'b))

Looking at the macro expansion there's something clearly wrong simply with the fact that the seq expression occurs in multiple places instead of just at the beginning of the macro expansion.



 Comments   
Comment by Emma Tosch [ 22/Jun/12 5:33 PM ]

https://gist.github.com/626088b01817ac638fae
Two expressions, macro-expanded. The only difference between the expressions is that the second occurrence in the second expression is seq'ed. The second let is the one throwing the exception; it's the one with the binding

(clojure.core/let [q_tail_3472 q_tail_3472
q_head_3471 q_head_3471
ocr-3470 (seq y)
z z]
...)





[MATCH-51] Fail to match empty vector Created: 21/Jan/12  Updated: 15/Jun/13  Resolved: 15/Jun/13

Status: Resolved
Project: core.match
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Jason Jackson Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   
(match (vector)
  ([(re :guard string?)] :seq) 4
  [] 6)

This should evaluate to 6 not nil.



 Comments   
Comment by Jason Jackson [ 21/Jan/12 9:30 AM ]

tested on 0.2.0-alpha10-SNAPSHOT

Comment by David Nolen [ 15/Jun/13 10:03 PM ]

resolved in master, added test case http://github.com/clojure/core.match/commit/b21d1a09e0d495003fc45ca48568355609ed69bd





[MATCH-53] Match doesn't work when AOT compiled into a JAR, but manually macroexpanding and JAR'ing works fine. Created: 24/Feb/12  Updated: 15/Jun/13  Resolved: 15/Jun/13

Status: Resolved
Project: core.match
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Kevin Lynagh Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

Code here:

https://gist.github.com/35fa11df7d7516abff50

Running lein uberjar on source containing the offending function, geo->svg, results in a non-working application.
However, if match is manually macroexpanded in the repl and the results pasted in, then the JAR works just fine.



 Comments   
Comment by Kevin Lynagh [ 24/Feb/12 2:27 PM ]

"non-working" meaning that the match always drops directly the :else clause.

Comment by Kevin Lynagh [ 24/Feb/12 6:09 PM ]

Updated code to minimal example. Problem persists with both Lein 1.7 and cake 0.6.3

Comment by David Nolen [ 25/Feb/12 7:35 PM ]

AOT bugs are a bit tricky to track down. Not sure how soon I'll be able to really dive into this one.

Comment by David Nolen [ 15/Jun/13 10:00 PM ]

this AOT case at least is resolved on master.





Generated at Tue Jun 18 02:38:21 CDT 2013 using JIRA 4.4#649-r158309.