In my Typed Racket program, I’m seeing this error:
any-wrap/c: contract violation
expected: acyclic value
given: #0=(foo #0#)
argument position: 1st
other arguments...:
What could cause this error?
This error is hard to diagnose, because it’s usually not at all clear what any-wrap/c
has to do with the code that’s signalling the error.
The problem here has to do with the way that casts
are handled in Typed Racket. Specifically, a value that’s passed with type Any
(which is most commonly the result of passing a Typed Racket value to untyped Racket) can pick up a contract wrapper, any-value/c
. If this value is cyclic (that is, there is a cycle of references within the value), the any-wrap/c
contract may fail. Here’s an example. This code actually uses the Any
type directly, rather than passing a value to untyped Racket.
#lang typed/racket
(require typed/rackunit)
(struct foo ([a : Any]) #:transparent #:mutable)
;; create a cyclic 'foo' structure
(define (make-cyclic-structure)
(define my-foo (foo 13))
(set-foo-a! my-foo my-foo)
my-foo)
;; pass a foo as an Any, then cast it and extract the field:
(define (take-any [x : Any]) : Any
(define its-a-foo (cast x foo))
(foo-a its-a-foo))
;; this causes the problem:
(take-any (make-cyclic-structure))
;; but so does this:
(check-equal? (make-cyclic-structure) 1234)
In this case, there are a number of fixes for the first of the two problematic lines. The simplest is just to change the type of the input to take-any
from Any
to foo
. Another one is to change (cast x foo)
into (assert x foo?)
; it turns out that using assert
can result in a value that isn’t wrapped in the same way. You could also use something like
(match x
[(foo a) x])
… which is a little clunky but gets the job done.
Repairing the second one (the use in a test case) can be done with e.g.
(check-true (equal? (make-cyclic-structure) 1234))
… which isn’t as nice (the fail message is just going to report that it wanted true and got false), but still performs the right test.