(module tc-lambda-unit (lib "a-unit.ss")
(require "planet-requires.ss"
"signatures.ss"
"types.ss" "types-aux.ss" "type-environments.ss" "lexical-env.ss" "type-annotation.ss" "effects.ss"
"utils.ss"
"tc-utils.ss"
(lib "match.ss"))
(require-for-template (lib "match.ss") "internal-forms.ss")
(require-libs)
(require (planet "environment.ss" ("cobbe" "environment.plt" 3 0)))
(require-for-template mzscheme)
(import typechecker^)
(export tc-lambda^)
(define (remove-var id thns elss)
(let/ec exit
(define (fail) (exit #f))
(define (rv e)
(match e
[($ var-true-effect v) (if (module-identifier=? v id) (make-latent-var-true-effect) (fail))]
[($ var-false-effect v) (if (module-identifier=? v id) (make-latent-var-false-effect) (fail))]
[(or ($ true-effect) ($ false-effect)) e]
[($ restrict-effect t v) (if (module-identifier=? v id) (make-latent-restrict-effect t) (fail))]
[($ remove-effect t v) (if (module-identifier=? v id) (make-latent-remove-effect t) (fail))]))
(cons (map rv thns) (map rv elss))))
(define (tc/lambda-clause args body)
(syntax-case args ()
[(args ...)
(let* ([arg-list (syntax->list #'(args ...))]
[arg-types (map get-type arg-list)])
(with-lexical-env/extend
arg-list arg-types
(match (tc-exprs (syntax->list body))
[($ tc-result t thn els)
(cond
[(and (= 1 (length arg-list)) (remove-var (car arg-list) thn els))
=> (lambda (thn/els) (make-arr arg-types t #f (car thn/els) (cdr thn/els)))]
[else (make-arr arg-types t)])]
[_ (int-err "bad match")])))]
[(args ... . rest)
(let* ([arg-list (syntax->list #'(args ...))]
[arg-types (map get-type arg-list)]
[rest-type (get-type #'rest)])
(with-lexical-env/extend
(cons #'rest arg-list)
(cons (make-Listof rest-type) arg-types)
(match-let ([($ tc-result t thn els) (tc-exprs (syntax->list body))])
(make-arr arg-types t rest-type))))]))
(define (tc/mono-lambda formals bodies)
(make-funty (map tc/lambda-clause (syntax->list formals) (syntax->list bodies))))
(define (tc/lambda form formals bodies)
(if (syntax-property form 'typechecker:plambda)
(tc/plambda form formals bodies)
(ret (tc/mono-lambda formals bodies))))
(define (tc/plambda form formals bodies)
(with-syntax ([tvars (syntax-property form 'typechecker:plambda)])
(let* ([literal-tvars (map syntax-e (syntax->list #'tvars))]
[new-tvars (map make-tvar literal-tvars)]
[ty (parameterize ([current-tvars (extend-env literal-tvars new-tvars (current-tvars))])
(tc/mono-lambda formals bodies))])
(ret (make-poly literal-tvars ty)))))
)