+ ;; (display "result of ")
+ ;; (display x)
+ ;; (display ":\n\t")
+ ;; (display (pretty-type (cadr res)))
+ ;; (display "\n\t[")
+ ;; (display (pretty-constraints (car res)))
+ ;; (display "]\n")
+ res))
+
+(define (init-adts-env prog)
+ (flat-map data-tors-type-env (program-data-layouts prog)))
+
+ ; we typecheck the lambda calculus only (only single arg lambdas)
+(define (typecheck prog)
+ (let ([expanded (expand-pattern-matches prog)])
+ (cadr (check (program-data-layouts prog)
+ (init-adts-env expanded)
+ (normalize (program-body expanded))))))
+
+
+ ; before passing annotated types onto codegen
+ ; we need to restore the pre-normalization structure
+ ; (this is important for function arity etc)
+(define (denormalize orig normed)
+
+ (define (collapse-lambdas n x)
+ (case n
+ [0 x]
+ [else
+ (let* ([inner-lambda (lambda-body (ann-expr x))]
+ [arg (lambda-arg (ann-expr x))]
+ [inner-collapsed (ann-expr (collapse-lambdas (- n 1) inner-lambda))])
+ `((lambda ,(cons arg (lambda-args inner-collapsed))
+ ,(lambda-body inner-collapsed)) : ,(ann-type x)))]))
+
+ (define (collapse-apps n x)
+ (case n
+ [-1 (error #f "nullary functions not handled yet")]
+ [0 x]
+ [else
+ (let* ([inner-app (car (ann-expr x))]
+ [inner-collapsed (collapse-apps (- n 1) inner-app)])
+ `(,(append (ann-expr inner-collapsed) (cdr (ann-expr x))) : ,(ann-type x)))]))
+
+ (case (ast-type orig)
+ ['lambda
+ (let ([collapsed (collapse-lambdas (- (length (lambda-args orig)) 1) normed)])
+ `((lambda ,(lambda-args (ann-expr collapsed))
+ ,(denormalize (lambda-body orig)
+ (lambda-body (ann-expr collapsed)))) : ,(ann-type collapsed)))]
+ ['app
+ (let ([collapsed (collapse-apps (- (length orig) 2) normed)])
+ `(,(map (lambda (o n) (denormalize o n)) orig (ann-expr collapsed))
+ : ,(ann-type collapsed)))]
+ ['let
+ `((let ,(map (lambda (o n) (list (car o) (denormalize (cadr o) (cadr n))))
+ (let-bindings orig)
+ (let-bindings (ann-expr normed)))
+ ,@(map denormalize
+ (let-body orig)
+ (let-body (ann-expr normed)))) : ,(ann-type normed))]
+ ['if `((if ,@(map denormalize (cdr orig) (cdr (ann-expr normed))))
+ : ,(ann-type normed))]
+ ['case `((case ,(denormalize (case-switch orig) (case-switch (ann-expr normed)))
+ ,@(map (lambda (o n) (cons (car o) (denormalize (cadr o) (cadr n))))
+ (case-cases orig) (case-cases (ann-expr normed))))
+ : ,(ann-type normed))]
+ [else normed]))
+
+(define ann-expr car)
+(define ann-type caddr)
+
+ ; prerequisites: expand-pattern-matches
+(define (annotate-types prog)
+ (denormalize
+ (program-body prog)
+ (caddr (check (program-data-layouts prog)
+ (init-adts-env prog)
+ (normalize (program-body prog))))))
+
+
+ ; returns a list of constraints
+(define (~ a b)
+ (let ([res (unify? a b)])
+ (if res
+ res
+ (error #f
+ (format "couldn't unify ~a ~~ ~a" a b)))))
+
+(define (unify? a b)
+ (cond [(eq? a b) '()]
+ [(tvar? a) (list (cons a b))]
+ [(tvar? b) (list (cons b a))]
+ [(and (abs? a) (abs? b))
+ (let* [(arg-cs (unify? (cadr a) (cadr b)))
+ (body-cs (unify? (substitute arg-cs (caddr a))
+ (substitute arg-cs (caddr b))))]
+ (constraint-merge body-cs arg-cs))]
+ [else #f]))
+
+(define (substitute cs t)
+ (cond
+ [(tvar? t)
+ (if (assoc t cs)
+ (cdr (assoc t cs))
+ t)]
+ [(abs? t) `(abs ,(substitute cs (cadr t))
+ ,(substitute cs (caddr t)))]
+ [else t]))
+
+ ; applies substitutions to all variables in environment