#lang s-exp macrotypes/examples/stlc+overloading
(require rackunit/macrotypes)

;; -----------------------------------------------------------------------------
;; --- syntax for ψ types

(typecheck-fail
 (signature (to-string0 α) (→ α Str Str))
 #:with-msg "Expected.*signature")

(typecheck-fail
 (signature (to-string0 α) (→ Str Str))
 #:with-msg "Expected.*signature")

(typecheck-fail
 (signature (to-string0 α) (→ α Str))
 #:with-msg "not allowed in an expression context")

;; -----------------------------------------------------------------------------
;; --- basic overloading

;; (signature (to-string α) (→ α Str))

;; (typecheck-fail
   ( to - string 1 )
   # : with - msg " Resolution for ' to - string ' failed " )

;; (typecheck-fail
;;  (to-string "yolo")
   # : with - msg " Resolution for ' to - string ' failed " )

;; ;; -- can later add cases to an overloaded name
  ( instance ( to - string  )
    ( λ ( [ x :  ] ) "  " ) )

  ( instance ( to - string  )
    ( λ ( [ x :  ] ) " string " ) )

;; (check-type
   ( to - string 3 )
   :  ⇒ "  " )

;; (typecheck-fail
;;  (to-string (+ 0 0))
   # : with - msg " Resolution for ' to - string ' failed " )

  ( instance ( to - string  )
    ( λ ( [ x :  ] ) " num " ) )

;; (check-type
   ( to - string ( + 2 2 ) )
   :  ⇒ " num " )

;; (check-type
;;  (to-string -1)
   :  ⇒ " num " )

;; (check-type
;;  (to-string "hi")
   :  ⇒ " string " )

;; ;; -- use 'resolve' to get exact matches

;; (check-type
   ( ( resolve to - string  ) 1 )
   :  ⇒ "  " )

;; (check-type
   ( ( resolve to - string  ) 1 )
   :  ⇒ " num " )

;; (typecheck-fail
;;  (resolve to-string Int)
   # : with - msg " Resolution for ' to - string ' failed " )

;; (typecheck-fail
   ( ( resolve to - string  ) " hello " )
;;  #:with-msg "expected: +Num\n *given: +Str\n *expressions: \"hello\"")

;; ;; -- instances are type-checked. They must match
;; (typecheck-fail
;;  (instance (to-string Int)
             ( λ ( [ x :  ] ) " num " ) )
;;  #:with-msg "must be the instance type")

;; (typecheck-fail
;;  (instance (to-string Int)
;;            (λ ([x : Int]) 0))
;;  #:with-msg "must match template codomain")

;; (typecheck-fail
;;  (instance (to-string Int)
             42 )
   # : with - msg " May only overload single - argument functions " )

;; ;; -- no overlapping instances
;; (typecheck-fail
   ( instance ( to - string  )
             ( λ ( [ x :  ] ) " wrong " ) )
;;  #:with-msg "Overlaps with existing instance")

;; -- can't instantiate non-overloadeds
(typecheck-fail
 (λ ([x : (→ Int Int)])
   (instance (x Int)
             0))
 #:with-msg "Identifier 'x' is not overloaded")

;; ;; -- explicit resolve

;; ;; -- recursive instances are fine [TODO really want (List α)]
  ( instance ( to - string ( List  ) )
            ( λ ( [ x : ( List  ) ] ) " listnat " ) )

;; (check-type
   ( to - string ( cons 1 ( cons 2 ( nil { Nat } ) ) ) )
   :  ⇒ " listnat " )

;; ;; -- higher-order use


 -----------------------------------------------------------------------------
 --- syntax for ψ types
 -----------------------------------------------------------------------------
 --- basic overloading
 (signature (to-string α) (→ α Str))
 (typecheck-fail
 (typecheck-fail
  (to-string "yolo")
 ;; -- can later add cases to an overloaded name
 (check-type
 (typecheck-fail
  (to-string (+ 0 0))
 (check-type
 (check-type
  (to-string -1)
 (check-type
  (to-string "hi")
 ;; -- use 'resolve' to get exact matches
 (check-type
 (check-type
 (typecheck-fail
  (resolve to-string Int)
 (typecheck-fail
  #:with-msg "expected: +Num\n *given: +Str\n *expressions: \"hello\"")
 ;; -- instances are type-checked. They must match
 (typecheck-fail
  (instance (to-string Int)
  #:with-msg "must be the instance type")
 (typecheck-fail
  (instance (to-string Int)
            (λ ([x : Int]) 0))
  #:with-msg "must match template codomain")
 (typecheck-fail
  (instance (to-string Int)
 ;; -- no overlapping instances
 (typecheck-fail
  #:with-msg "Overlaps with existing instance")
 -- can't instantiate non-overloadeds
 ;; -- explicit resolve
 ;; -- recursive instances are fine [TODO really want (List α)]
 (check-type
 ;; -- higher-order use
#lang s-exp macrotypes/examples/stlc+overloading
(require rackunit/macrotypes)


(typecheck-fail
 (signature (to-string0 α) (→ α Str Str))
 #:with-msg "Expected.*signature")

(typecheck-fail
 (signature (to-string0 α) (→ Str Str))
 #:with-msg "Expected.*signature")

(typecheck-fail
 (signature (to-string0 α) (→ α Str))
 #:with-msg "not allowed in an expression context")



   ( to - string 1 )
   # : with - msg " Resolution for ' to - string ' failed " )

   # : with - msg " Resolution for ' to - string ' failed " )

  ( instance ( to - string  )
    ( λ ( [ x :  ] ) "  " ) )

  ( instance ( to - string  )
    ( λ ( [ x :  ] ) " string " ) )

   ( to - string 3 )
   :  ⇒ "  " )

   # : with - msg " Resolution for ' to - string ' failed " )

  ( instance ( to - string  )
    ( λ ( [ x :  ] ) " num " ) )

   ( to - string ( + 2 2 ) )
   :  ⇒ " num " )

   :  ⇒ " num " )

   :  ⇒ " string " )


   ( ( resolve to - string  ) 1 )
   :  ⇒ "  " )

   ( ( resolve to - string  ) 1 )
   :  ⇒ " num " )

   # : with - msg " Resolution for ' to - string ' failed " )

   ( ( resolve to - string  ) " hello " )

             ( λ ( [ x :  ] ) " num " ) )


             42 )
   # : with - msg " May only overload single - argument functions " )

   ( instance ( to - string  )
             ( λ ( [ x :  ] ) " wrong " ) )

(typecheck-fail
 (λ ([x : (→ Int Int)])
   (instance (x Int)
             0))
 #:with-msg "Identifier 'x' is not overloaded")


  ( instance ( to - string ( List  ) )
            ( λ ( [ x : ( List  ) ] ) " listnat " ) )

   ( to - string ( cons 1 ( cons 2 ( nil { Nat } ) ) ) )
   :  ⇒ " listnat " )


