www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit dfaab96a29c50f0bd041319d95b6455930ffd183
parent 5c8300a538dc5f3edadb2ae4945687b5df9c8b68
Author: Ben Greenman <types@ccs.neu.edu>
Date:   Thu, 15 Oct 2015 14:31:31 -0400

[o+] check for same-arity functions in unions

Diffstat:
Mtapl/stlc+occurrence.rkt | 76++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mtapl/tests/stlc+occurrence-tests.rkt | 8++++----
2 files changed, 50 insertions(+), 34 deletions(-)

diff --git a/tapl/stlc+occurrence.rkt b/tapl/stlc+occurrence.rkt @@ -67,6 +67,7 @@ ;; flatten nested unions (begin-for-syntax + (define τ-eval (current-type-eval)) (define (τ->symbol τ) @@ -84,36 +85,51 @@ [_ (error 'τ->symbol (~a (syntax->datum τ)))])) - (define (∪-eval τ-stx) - (syntax-parse (τ-eval τ-stx) - [(~∪ τ-stx* ...) - ;; Recursively evaluate members - (define τ** - (for/list ([τ (in-list (syntax->list #'(τ-stx* ...)))]) - (let ([τ+ (∪-eval τ)]) - (if (∪? τ+) - (∪->list τ+) - (list τ+))))) - ;; Remove duplicates from the union, sort members - (define τ* - (sort - (remove-duplicates (apply append τ**) (current-type=?)) - symbol<? - #:key τ->symbol)) - ;; Check for empty & singleton lists - (define τ - (cond - [(null? τ*) - (raise-user-error 'τ-eval "~a (~a:~a) empty union type ~a\n" - (syntax-source τ-stx) (syntax-line τ-stx) (syntax-column τ-stx) - (syntax->datum τ-stx))] - [(null? (cdr τ*)) - #`#,(car τ*)] - [else - #`#,(cons #'∪ τ*)])) - (τ-eval τ)] - [_ - (τ-eval τ-stx)])) + (define ∪-eval + ;; Private helper: check that all functions have unique arities + ;; It's private because it assumes all τ* have been evaluated + (let ([assert-unique-arity-arrows + (lambda (τ*) + (for/fold ([seen '()]) + ([τ (in-list τ*)]) + (syntax-parse τ + [(~→ τ-dom* ... τ-cod) + (define arity (stx-length #'(τ-dom* ...))) + (when (memv arity seen) + (error '∪ (format "Cannot discriminate types in the union ~a. Multiple functions have arity ~a." (cons '∪ (map syntax->datum τ*)) arity))) + (cons arity seen)] + [_ seen])))]) + (lambda (τ-stx) + (syntax-parse (τ-eval τ-stx) + [(~∪ τ-stx* ...) + ;; Recursively evaluate members + (define τ** + (for/list ([τ (in-list (syntax->list #'(τ-stx* ...)))]) + (let ([τ+ (∪-eval τ)]) + (if (∪? τ+) + (∪->list τ+) + (list τ+))))) + ;; Remove duplicates from the union, sort members + (define τ* + (sort + (remove-duplicates (apply append τ**) (current-type=?)) + symbol<? + #:key τ->symbol)) + ;; Check for empty & singleton lists + (define τ + (cond + [(null? τ*) + (raise-user-error 'τ-eval "~a (~a:~a) empty union type ~a\n" + (syntax-source τ-stx) (syntax-line τ-stx) (syntax-column τ-stx) + (syntax->datum τ-stx))] + [(null? (cdr τ*)) + #`#,(car τ*)] + [else + (assert-unique-arity-arrows τ*) + #`#,(cons #'∪ τ*)])) + (τ-eval τ)] + [_ + (τ-eval τ-stx)])))) (current-type-eval ∪-eval)) ;; ----------------------------------------------------------------------------- diff --git a/tapl/tests/stlc+occurrence-tests.rkt b/tapl/tests/stlc+occurrence-tests.rkt @@ -272,8 +272,8 @@ ;; ----------------------------------------------------------------------------- ;; --- Functions in union -(check-type (λ ([x : (∪ Int (∪ Nat) (∪ (→ Int Int)) (→ (→ (→ Int Int)) Int))]) #t) - : (→ (∪ Int Nat (→ Int Int) (→ (→ (→ Int Int)) Int)) Boolean)) +(check-type (λ ([x : (∪ Int (∪ Nat) (∪ (→ Int Str Int)) (→ (→ (→ Int Int)) Int))]) #t) + : (→ (∪ Int Nat (→ Int Str Int) (→ (→ (→ Int Int)) Int)) Boolean)) (check-type (λ ([x : (∪ Int (→ Int Int))]) #t) : (→ Int Boolean)) @@ -324,8 +324,8 @@ ;; --- disallow same-arity functions (typecheck-fail - (λ ([x : (∪ (→ Int Int) (→ Str Str))]) (x 1)) - #:with-msg "boooo") + (λ ([x : (∪ (→ Int Int) (→ Str Str))]) 1) + #:with-msg "Cannot discriminate") ;; ----------------------------------------------------------------------------- ;; --- TODO Filter values (should do nothing)