<< Back to previous view

[CTYP-68] assoc, update-in &c have record-hostile types Created: 22/Sep/13  Updated: 09/Oct/13  Resolved: 25/Sep/13

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

Type: Defect Priority: Major
Reporter: Julian Birch Assignee: Ambrose Bonnaire-Sergeant
Resolution: Completed Votes: 0
Labels: None


(use 'clojure.core.typed)
user=> (ann-record X [x :- Number])
user=> (defrecord X [x])
user=> (cf (assoc (X. 3) :x 3) X)

0.2.7 thought this should be (Map Any Any)
0.2.9 just thinks you can't do it at all

but it should pass.

Comment by Chris Spencer [ 22/Sep/13 10:59 AM ]

Had a quick look

; inside assoc-type-pairs
(println t (type t) (r/Record? t))

; repl
(ann-record X [x :- Number])
(defrecord X [x])
(cf (assoc (X. 3) :x 3) X)
; debug: user.X clojure.core.typed.type_rep.RClass false

So looks like result of (X. 3) is being instantiated as an RClass rather than a DataType?

Comment by Chris Spencer [ 22/Sep/13 11:12 AM ]

Found issue:

(cf (ann-record X [x :- Number]))
(cf (assoc (X. 3) :x 3))
; user.X clojure.core.typed.type_rep.DataType true

ann-record doesn't collect so need to wrap in a cf, just awkward

Comment by Ambrose Bonnaire-Sergeant [ 22/Sep/13 10:07 PM ]

Global annotations are only collected during type checking.

I've tried to document this, but it seems to frequently trip people up. I've tried to ensure error messages based on missing annotations emphasise annotations must be provided via cf.

eg. https://github.com/clojure/core.typed/wiki/Quick-Guide#type-checking-is-separate-to-compilation-and-must-be-explicitly-run

FWIW this might change in the future to defonce semantics.

There are a couple of other issues here.

1. The Java constructor X. type checked because datatype constructors are normal Java constructors that take Object. ann-record overrides constructors to take the field types.

A couple of approaches to fixing this:

  • warn if constructing an IType or IRecord that is unannotated
  • recommend avoiding the Java constructor in favour of the positional factory.

2. update-in is NYI, ticket here http://dev.clojure.org/jira/browse/CTYP-8

3. assoc might be too strict now. X implements IPersistentMap, so it should be able to assoc anything even if it is unannotated.

(cf (assoc (X. 3) :x 3)) should return (IPersistentMap Any Any).

(defrecord X [x])
(cf (assoc (X. 3) :x 3))

Type Error (clojure.core.typed:1:34) Cannot assoc args `[(Value :x) {:then tt, :else ff}] [(Value 3) {:then tt, :else ff}]` on clojure.core.ty
ExceptionInfo Type Checker: Found 1 error  clojure.core/ex-info (core.clj:4327)
Comment by Julian Birch [ 24/Sep/13 2:58 PM ]

OK, assoc seems to be behaving itself under 0.2.11.

I should point out I'm using lein typed most of the time, so I'm not that familiar with the repl. I should probably confine myself to submitting scripts that lein typed can run...

This passed, and I think should pass:

(ann-record X [x :- Number])
(defrecord X [x])
(ann Z [-> X])
(defn Z [] (assoc (X. 3) :x 3))

Comment by Ambrose Bonnaire-Sergeant [ 25/Sep/13 3:13 AM ]

Ok. Also it would be helpful to include the actual type error or stacktrace in issues.

Generated at Tue Jun 28 08:15:25 CDT 2016 using JIRA 4.4#649-r158309.