core.typed

assoc, update-in &c have record-hostile types

Details

  • Type: Defect Defect
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Completed
  • Affects Version/s: 0.2.0
  • Fix Version/s: None
  • Component/s: None
  • Labels:
    None

Description

(use 'clojure.core.typed)
nil
user=> (ann-record X [x :- Number])
nil
user=> (defrecord X [x])
user.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.

Activity

Hide
Chris Spencer added a comment -

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?

Show
Chris Spencer added a comment - 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?
Hide
Chris Spencer added a comment -

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

Show
Chris Spencer added a comment - 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
Hide
Ambrose Bonnaire-Sergeant added a comment - - edited

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
ped.X
ExceptionInfo Type Checker: Found 1 error  clojure.core/ex-info (core.clj:4327)
Show
Ambrose Bonnaire-Sergeant added a comment - - edited 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
ped.X
ExceptionInfo Type Checker: Found 1 error  clojure.core/ex-info (core.clj:4327)
Hide
Julian Birch added a comment -

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))

Show
Julian Birch added a comment - 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))
Hide
Ambrose Bonnaire-Sergeant added a comment -

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

Show
Ambrose Bonnaire-Sergeant added a comment - Ok. Also it would be helpful to include the actual type error or stacktrace in issues.

People

Vote (0)
Watch (0)

Dates

  • Created:
    Updated:
    Resolved: