#lang racket/base

(provide cast-table-ref
         cast-table-add!)

(require syntax/id-table)

;; A module that helps store information about the original types of casted
;; expressions.
;;
;; Casts in Typed Racket must generate two contracts. One from typed to untyped,
;; and another from untyped to typed. The contract from typed to untyped is
;; generated based on the existing type of the expression, which must be stored
;; in this table so that it can be looked up later in the contract-generation
;; pass.
;;
;; If a cast is within a `case->` functions, it is typechecked with multiple
;; types. The cast table holds all of those types, and the contract layer
;; must protect values of any one of those types. This is why the cast-table
;; contains lists, and why `cast-table-ref` returns a list on success.

;; cast-table : (Free-Id-Tableof (Listof Type-Stx))
;; interpretation:
;;   A mapping from lifted-contract-def identifiers to the possible existing
;;   types of values that the contract has to protect as they go from typed
;;   to untyped code.
(define cast-table (make-free-id-table))

;; cast-table-add! : Id Type-Stx -> Void
;; Associates the given type with the given contract-def identifier, to signify
;; that the contract generated by `id` must protect values of type `type-stx`.
(define (cast-table-add! id type-stx)
  (free-id-table-update! cast-table id
    (λ (lst) (cons type-stx lst))
    (λ () '())))

;; cast-table-ref : Id -> (U False (Listof Type-Stx))
;; On success, returns a list containing all the types of values that the
;; contract must project as they go from typed to untyped code. On failure,
;; returns false.
(define (cast-table-ref id)
  (free-id-table-ref cast-table id #f))
