code cleanup

This commit is contained in:
Stephen Chang 2016-04-13 15:14:57 -04:00
parent 8a36c7962b
commit 6cb15a06da
5 changed files with 129 additions and 265 deletions

View File

@ -43,9 +43,8 @@
; should only be monomorphic?
[((~∀ () (~ext-stlc:→ τ1 ...)) (~∀ () (~ext-stlc:→ τ2 ...)))
(compute-constraints #'((τ1 τ2) ...))]
[_ #:when #t #;(printf "shouldnt get here. could not unify: ~a\n" τ1-τ2) #'()]))
(define (compute-constraints τs)
;(printf "constraints: ~a\n" (syntax->datum τs))
[_ #'()]))
(define (compute-constraints τs)
(stx-appendmap compute-constraint τs))
(define (solve-constraint x-τ)
@ -136,24 +135,10 @@
;; top-lvl fns, since they can call each other
#:with (~and ty_fn_expected (~∀ _ (~ext-stlc:→ _ ... out_expected)))
((current-type-eval) #'( Ys (ext-stlc:→ τ+orig ...)))
;; #:with [_ _ (~and ty_fn_actual (~∀ _ (~ext-stlc:→ _ ... out_actual)))]
;; (infer/ctx+erase #'([f : ty_fn_expected]) ; need to handle recursive fn calls
;; #'(Λ Ys (ext-stlc:λ ([x : τ] ...) (ext-stlc:begin e_body ... e_ann))))
;; #:fail-unless (typecheck? #'ty_fn_actual #'ty_fn_expected)
;; (format
;; "Function ~a's body ~a has type ~a, which does not match given type ~a."
;; (syntax->datum #'f) (syntax->datum #'e)
;; (type->str #'out_actual) (type->str #'τ_out))
#`(begin
(define-syntax f
(make-rename-transformer
;(⊢ g : (∀ Ys (ext-stlc:→ τ ... τ_out)))))
( g : ty_fn_expected #;( Ys (ext-stlc:→ τ+orig ...)))))
(define-syntax f (make-rename-transformer ( g : ty_fn_expected)))
(define g
(Λ Ys (ext-stlc:λ ([x : τ] ...) (ext-stlc:begin e_body ... e_ann)))))]
#;(begin
(define-syntax f (make-rename-transformer ( g : ( (X ...) (ext-stlc:→ τ ... τ_out)))))
(define g (Λ (X ...) (ext-stlc:λ ([x : τ] ...) e_ann))))
[(_ (f:id x:id ...) (~datum :) ty ... (~or (~datum ->) (~datum )) ty_out . b)
#'(define/tc (f [x : ty] ... -> ty_out) . b)]
[(_ (f:id [x:id (~datum :) τ] ... (~or (~datum ->) (~datum )) τ_out) e_body ... e)
@ -179,19 +164,8 @@
((current-type-eval) #'( Ys (ext-stlc:→ τ+orig ...)))
'orig
(list #'( τ+orig ...)))
;; #:with [_ _ (~and ty_fn_actual (~∀ _ (~ext-stlc:→ _ ... out_actual)))]
;; (infer/ctx+erase #'([f : ty_fn_expected]) ; need to handle recursive fn calls
;; #'(Λ Ys (ext-stlc:λ ([x : τ] ...) (ext-stlc:begin e_body ... e_ann))))
;; #:fail-unless (typecheck? #'ty_fn_actual #'ty_fn_expected)
;; (format
;; "Function ~a's body ~a has type ~a, which does not match given type ~a."
;; (syntax->datum #'f) (syntax->datum #'e)
;; (type->str #'out_actual) (type->str #'τ_out))
#`(begin
(define-syntax f
(make-rename-transformer
;(⊢ g : (∀ Ys (ext-stlc:→ τ ... τ_out)))))
( g : ty_fn_expected #;( Ys (ext-stlc:→ τ+orig ...)))))
(define-syntax f (make-rename-transformer ( g : ty_fn_expected)))
(define g
(Λ Ys (ext-stlc:λ ([x : τ] ...) (ext-stlc:begin e_body ... e_ann)))))])
@ -214,12 +188,8 @@
(Cons [fld (~datum :) τ] ...)
(~and (Cons τ ...)
(~parse (fld ...) (generate-temporaries #'(τ ...)))))) ...)
#:with RecName (generate-temporary #'Name)
#:with NameExpander (format-id #'Name "~~~a" #'Name)
#:with NameExtraInfo (format-id #'Name "~a-extra-info" #'Name)
#:with NameDelayed (format-id #'Name "~a-delayed" #'Name)
#:with NameForced (format-id #'NameDelayed "~a-force" #'NameDelayed)
#:with NameForcedExpander (format-id #'NameForced "~~~a" #'NameForced)
#:with (StructName ...) (generate-temporaries #'(Cons ...))
#:with ((e_arg ...) ...) (stx-map generate-temporaries #'((τ ...) ...))
#:with ((e_arg- ...) ...) (stx-map generate-temporaries #'((τ ...) ...))
@ -227,47 +197,13 @@
#:with ((acc ...) ...) (stx-map (λ (S fs) (stx-map (λ (f) (format-id S "~a-~a" S f)) fs))
#'(StructName ...) #'((fld ...) ...))
#:with (Cons? ...) (stx-map mk-? #'(StructName ...))
#:with (Y ...) (generate-temporaries #'(X ...))
;; types, but using RecName instead of Name
#:with ((τ/rec ...) ...) (subst #'RecName #'Name #'((τ ...) ...))
#`(begin
; (define NameDelayed (lambda () (error "types not allowed at runtime")))
; TODO: use define-type-constructor for delayed form as well,
;; to get proper pattern expanders, etc
;; (define-syntax (Name stx)
;; (syntax-parse stx
;; [(_ Y ...) (add-orig (mk-type #'(delay NameDelayed Y ...)) stx)]))
(define-syntax (NameExtraInfo stx)
(syntax-parse stx
[(_ X ...) #'(('Cons 'StructName Cons? [acc τ] ...) ...)]))
(define-type-constructor Name
#:arity = #,(stx-length #'(X ...))
#:extra-info 'NameExtraInfo
; #:extra-info (X ...) (('Cons 'StructName Cons? [acc τ] ...) ...)
#:no-provide)
#;(define-type-constructor Name
#:arity = #,(stx-length #'(X ...))
#:extra-info (X ...)
(λ (RecName)
(let-syntax
([RecName
(syntax-parser
[(_ Y ...)
;; - this is a placeholder to break the recursion
;; - clients, like match, must manually unfold by
;; replacing the entire (#%plain-app RecName ...) stx
;; - to preserve polymorphic recursion, the entire stx
;; should be replaced but with X ... as the args
;; in place of args in the input type
;; (see subst-special in typecheck.rkt)
(assign-type #'(#%plain-app RecName Y ...) #'#%type)]
[(~and err (_ . rst))
(type-error #:src #'err
#:msg (format "type constructor ~a expects ~a args, given ~a: ~a"
(syntax->datum #'Name) (stx-length #'(X ...))
(stx-length #'rst) (string-join (stx-map type->str #'rst) ", ")))]
)])
('Cons 'StructName Cons? [acc τ/rec] ...) ...))
#:no-provide)
(struct StructName (fld ...) #:reflection-name 'Cons #:transparent) ...
(define-syntax (Cons stx)
@ -280,7 +216,6 @@
#:with τ-expected (syntax-property #'C 'expected-type)
#:fail-unless (syntax-e #'τ-expected)
(type-error #:src stx #:msg "cannot infer type of ~a; add annotations" #'C)
; #:with (_ (~datum delay) (_ () _ τ-expected-arg (... ...))) ((current-type-eval) #'τ-expected)
#:with (NameExpander τ-expected-arg (... ...)) ((current-type-eval) #'τ-expected)
#'(C {τ-expected-arg (... ...)})]
[_:id
@ -334,14 +269,9 @@
[{(~datum _)} #'()]
[{(~literal stlc+cons:nil)} #'()]
[{A:id} ; disambiguate 0-arity constructors (that don't need parens)
;; #:with ((~literal #%plain-lambda) (RecName)
;; ((~literal let-values) ()
;; ((~literal let-values) ()
;; . info-body)))
#:when (get-extra-info #'ty)
#'()]
;; comma tup syntax always has parens
; [{(~and ps (p1 ((~literal unquote) p2) ((~literal unquote) p) ...))}
[{(~and ps (p1 (unq p) ...))}
#:when (not (stx-null? #'(p ...)))
#:when (andmap (lambda (u) (equal? u 'unquote)) (syntax->datum #'(unq ...)))
@ -351,12 +281,7 @@
[((~datum _) ty) #'()]
[((~or (~literal stlc+cons:nil)) ty) #'()]
[(A:id ty) ; disambiguate 0-arity constructors (that don't need parens)
#:with (_ (_ ((~literal quote) C) . _) ...)
;; ((~literal #%plain-lambda) (RecName)
;; ((~literal let-values) ()
;; ((~literal let-values) ()
;; . (((~literal #%plain-app) ((~literal quote) C) . rst) ...))))
(get-extra-info #'ty)
#:with (_ (_ (_ C) . _) ...) (get-extra-info #'ty)
#:when (member (syntax->datum #'A) (syntax->datum #'(C ...)))
#'()]
[(x:id ty) #'((x ty))]
@ -379,21 +304,15 @@
#:with (~List t) #'ty
(unifys #'([p t] [ps ty]))]
[((Name p ...) ty)
;; #:with ((~literal #%plain-lambda) (RecName)
;; ((~literal let-values) ()
;; ((~literal let-values) ()
;; . info-body)))
;; (get-extra-info #'ty)
; #:with (_ (_ ((~literal quote) ConsAll) . _) ...) (get-extra-info #'ty)
; #:with info-unfolded (subst-special #'τ_e #'RecName #'info-body)
#:with (_ ((~literal quote) Cons) ((~literal quote) StructName) Cons? [_ acc τ] ...)
(stx-findf
(syntax-parser
[(_ 'C . rst)
(equal? (syntax->datum #'Name) (syntax->datum #'C))])
(stx-cdr (get-extra-info #'ty)))
(unifys #'([p τ] ...))]
[p+t #:fail-when #t (format "could not unify ~a" (syntax->datum #'p+t)) #'()]))
#:with (_ (_ Cons) _ _ [_ _ τ] ...)
(stx-findf
(syntax-parser
[(_ 'C . rst)
(equal? (syntax->datum #'Name) (syntax->datum #'C))])
(stx-cdr (get-extra-info #'ty)))
(unifys #'([p τ] ...))]
[p+t #:fail-when #t (format "could not unify ~a" (syntax->datum #'p+t))
#'()]))
(define (unifys p+tys) (stx-appendmap unify-pat+ty p+tys))
(define (compile-pat p ty)
@ -403,15 +322,9 @@
[{(~datum _)} #'_]
[{(~literal stlc+cons:nil)} (syntax/loc p (list))]
[{A:id} ; disambiguate 0-arity constructors (that don't need parens)
;; #:with ((~literal #%plain-lambda) (RecName)
;; ((~literal let-values) ()
;; ((~literal let-values) ()
;; . info-body)))
#:when (get-extra-info ty)
(compile-pat #'(A) ty)]
;; comma tup stx always has parens
;; comma tup syntax always has parens
; [{(~and ps (p1 ((~literal unquote) p2) ((~literal unquote) p) ...))}
[{(~and ps (p1 (unq p) ...))}
#:when (not (stx-null? #'(p ...)))
#:when (andmap (lambda (u) (equal? u 'unquote)) (syntax->datum #'(unq ...)))
@ -421,12 +334,8 @@
[(~literal stlc+cons:nil) ; nil
#'(list)]
[A:id ; disambiguate 0-arity constructors (that don't need parens)
;; #:with ((~literal #%plain-lambda) (RecName)
;; ((~literal let-values) ()
;; ((~literal let-values) ()
;; . (((~literal #%plain-app) ((~literal quote) C) . rst) ...))))
#:with (_ (_ ((~literal quote) C) . _) ...) (get-extra-info ty)
#:when (member (syntax->datum #'A) (syntax->datum #'(C ...)))
#:with (_ (_ (_ C) . _) ...) (get-extra-info ty)
#:when (member (syntax->datum #'A) (syntax->datum #'(C ...)))
(compile-pat #'(A) ty)]
[x:id p]
[(p1 (unq p) ...) ; comma tup stx
@ -454,14 +363,7 @@
#:with ps- (compile-pat #'ps ty)
#'(cons p- ps-)]
[(Name . pats)
;; #:with ((~literal #%plain-lambda) (RecName)
;; ((~literal let-values) ()
;; ((~literal let-values) ()
;; . info-body)))
;; (get-extra-info ty)
;; #:with ((_ ((~literal quote) ConsAll) . _) ...) #'info-body
;; #:with info-unfolded (subst-special #'τ_e #'RecName #'info-body)
#:with (_ ((~literal quote) Cons) ((~literal quote) StructName) Cons? [_ acc τ] ...)
#:with (_ (_ Cons) (_ StructName) _ [_ _ τ] ...)
(stx-findf
(syntax-parser
[(_ 'C . rst)
@ -513,14 +415,7 @@
(syntax->list #'((p ...) ...)))])])]
[else ; algebraic datatypes
(syntax-parse (get-extra-info ty)
[#;((~literal #%plain-lambda) (RecName)
((~literal let-values) ()
((~literal let-values) ()
. (((~literal #%plain-app)
((~literal quote) C)
((~literal quote) Cstruct)
. rst) ...))))
(_ (_ ((~literal quote) C) ((~literal quote) Cstruct) . rst) ...)
[(_ (_ (_ C) (_ Cstruct) . rst) ...)
(syntax-parse pats
[((Cpat _ ...) ...)
(define Cs (syntax->datum #'(C ...)))
@ -538,6 +433,7 @@
#t])]
[_ #t])]))
;; TODO: do get-ctx and compile-pat in one pass
(define (compile-pats pats ty)
(stx-map (lambda (p) (list (get-ctx p ty) (compile-pat p ty))) pats))
)
@ -553,13 +449,11 @@
(lambda (ps) (syntax-parse ps [(pp ...) (syntax/loc stx {pp ...})]))
#'((p ...) ...))
#:with ([(~and ctx ([x ty] ...)) pat-] ...) (compile-pats #'(pat ...) #'τ_e)
;; #:with ((~and ctx ([x ty] ...)) ...) (stx-map (lambda (p) (get-ctx p #'τ_e)) #'(pat ...))
#:with ty-expected (get-expected-type stx)
#:with ([(x- ...) e_body- ty_body] ...)
(stx-map
infer/ctx+erase
#'(ctx ...) #'((add-expected e_body ty-expected) ...))
;; #:with (pat- ...) (stx-map (lambda (p) (compile-pat p #'τ_e)) #'(pat ...))
#:fail-unless (same-types? #'(ty_body ...))
(string-append "branches have different types, given: "
(string-join (stx-map type->str #'(ty_body ...)) ", "))
@ -569,7 +463,6 @@
])]))
(define-typed-syntax match #:datum-literals (with)
; (syntax-parse stx #:datum-literals (with)
[(_ e with . clauses)
#:fail-when (null? (syntax->list #'clauses)) "no clauses"
#:with [e- τ_e] (infer+erase #'e)
@ -594,7 +487,9 @@
[([(~or (~and (~and xs [x ...]) (~parse rst (generate-temporary)))
(~and (~seq (~seq x ::) ... rst:id) (~parse xs #'())))
-> e_body] ...)
#:fail-unless (stx-ormap (lambda (xx) (and (brack? xx) (zero? (stx-length xx)))) #'(xs ...))
#:fail-unless (stx-ormap
(lambda (xx) (and (brack? xx) (zero? (stx-length xx))))
#'(xs ...))
"match: missing empty list case"
#:fail-when (and (stx-andmap brack? #'(xs ...))
(= 1 (stx-length #'(xs ...))))
@ -625,16 +520,9 @@
[([Clause:id x:id ...
(~optional (~seq #:when e_guard) #:defaults ([e_guard #'(ext-stlc:#%datum . #t)]))
-> e_c_un] ...) ; un = unannotated with expected ty
;; len #'clauses maybe > len #'info, due to guards
;; #:with ((~literal #%plain-lambda) (RecName)
;; ((~literal let-values) ()
;; ((~literal let-values) ()
;; . info-body)))
;; (get-extra-info #'τ_e)
;; #:with info-unfolded (subst-special #'τ_e #'RecName #'info-body)
;; length #'clauses may be > length #'info, due to guards
#:with info-body (get-extra-info #'τ_e)
#:with info-unfolded #'info-body
#:with (_ (_ ((~literal quote) ConsAll) . _) ...) #'info-body
#:with (_ (_ (_ ConsAll) . _) ...) #'info-body
#:fail-unless (set=? (syntax->datum #'(Clause ...))
(syntax->datum #'(ConsAll ...)))
(type-error #:src stx
@ -646,14 +534,13 @@
(syntax->datum #'(ConsAll ...))
(syntax->datum #'(Clause ...))))
", ")))
#:with ((_ ((~literal quote) Cons) ((~literal quote) StructName) Cons? [_ acc τ] ...) ...)
#:with ((_ _ _ Cons? [_ acc τ] ...) ...)
(map ; ok to compare symbols since clause names can't be rebound
(lambda (Cl)
(stx-findf
(syntax-parser
[((~literal #%plain-app) 'C . rst)
(equal? Cl (syntax->datum #'C))])
(stx-cdr #'info-unfolded))) ; drop leading #%app
[(_ 'C . rst) (equal? Cl (syntax->datum #'C))])
(stx-cdr #'info-body))) ; drop leading #%app
(syntax->datum #'(Clause ...)))
;; this commented block experiments with expanding to unsafe ops
;; #:with ((acc ...) ...) (stx-map
@ -781,8 +668,10 @@
(define old-orig (get-orig tyin))
(define new-orig
(and old-orig
(substs (stx-map get-orig #'tys-solved) #'Xs old-orig
(lambda (x y) (equal? (syntax->datum x) (syntax->datum y))))))
(substs
(stx-map get-orig #'tys-solved) #'Xs old-orig
(lambda (x y)
(equal? (syntax->datum x) (syntax->datum y))))))
(syntax-property tyin 'orig (list new-orig)))
#'(τ_in ...)))
( (#%app e_fn- e_arg- ...) : τ_out)])])]
@ -931,8 +820,7 @@
[(_ start)
#:with start- ( start as Int)
( (in-naturals start-) : (Sequence Int))])
(define-typed-syntax in-vector
[(_ e)

View File

@ -1,3 +1,61 @@
2016-04-13:
Summary of the extra-info problem.
Problem: datatypes need to know all constructors and argument types
- to properly do matching
- but storing this info as part of the type leads to looping for recursive
and mutually recursive types, since the canonical form of all types is
full expansion
Current solution:
- for each type TY, define:
- standard TY macro via define-type-constructor
- with extra-info = name of additional macro
- additional "extra-info" macro that expands into needed datatype clause info
- this solution addresses many issues:
- breaks the recursion (ie inf looping) in type macros
- is much faster, since it avoids the type traversals I was doing to manually
unroll recursive types (see subst-special and subst-expr)
- allows for substing of quantified tyvars to occur naturally,
since the types are passed into the extra-info macro
What didnt work:
- quoting the extra-info (or parts of it) to avoid infinite expansion
- summary:
- must be exposed to expansion:
- struct accessors
- any type vars
- cannot be exposed to expansion:
- call to recursive and mutually recursive type constructors
- tried a complicated solution where I used "sentinel" stxs
to accumulate the context that the quoted parts were missing
- was complicated when needing to instantiate forall types
- and didnt fully work for nested datatypes
- manually subst out recursive calls
- essentially, this required me to manually manage the recursive types,
including, a la tapl, including unrolling in match
- was very performance costly (see subst-special and subst-expr)
- this solution does work with mutually recursive types (still inf loops)
- store extra-info as stx-property
- figured out how to use make-syntax-delta-introducer to sync up unexpanded
props, so that it may be instantiated properly
- but something doesnt work (specifically match) when types are provided
- works if everything is defined in the same file
- ie, inline basics-general in basics2
- doesnt work if (provide (struct-out ...)) is inserted directly in mlish.rkt
- couldnt get it to work if Cons? is assigned different contexts in match
- eg context of e-, or τ_e
- direct match on constructor is fine (see Bool use in bg/basics2.mlish)
- but doesnt work when passed through fn call (see bool-id in basics2)
- essentially, struct accessors and predicates must be exposed to expansion
error is:
; require: namespace mismatch;
; reference to a module that is not available
; reference phase: 0
; referenced module: 'basics-general
; referenced phase level: 0
; in: True26?
2016-02-29
Problem: storing variant info as properties
- when instantiating polymorphic type, need to instantiate properties as well

View File

@ -1,6 +1,6 @@
#lang racket/base
(require "mlish-tests.rkt")
;(require "mlish/queens.mlish")
(require "mlish/queens.mlish")
(require "mlish/listpats.mlish")
(require "mlish/match2.mlish")
(require "mlish/polyrecur.mlish")

View File

@ -1,6 +1,6 @@
#lang racket/base
(require "mlish/queens.mlish")
;(require "mlish/queens.mlish")
;; shootout tests
(require "mlish/trees-tests.mlish")

View File

@ -134,12 +134,10 @@
(define-syntax add-expected
(syntax-parser
[(_ e τ)
; #:when (printf "adding expected type ~a to expression ~a\n"
; (syntax->datum #'τ) (syntax->datum #'e))
(syntax-property #'e 'expected-type #'τ)]))
[(_ e τ) (syntax-property #'e 'expected-type #'τ)]))
(define-for-syntax (add-expected-ty e ty)
(or (and (syntax-e ty) (syntax-property e 'expected-type ((current-type-eval) ty)))
(or (and (syntax-e ty)
(syntax-property e 'expected-type ((current-type-eval) ty)))
e))
;; type assignment
@ -213,10 +211,6 @@
['x (syntax-e #'x)]
[_ (syntax->datum #'e-)])
'tycon (type->str #'τ_e))
#;(if (stx-pair? #'τ_e)
(syntax-parse #'τ_e
[(τ-expander . args) #'(e- args)])
#'e-)
(syntax-parse #'τ_e
[(τ-expander . args) #'(e- args)]
[_ #'e-])])]))
@ -243,10 +237,6 @@
;#:with args (τ-get #'τ_e)
#:with res
(stx-map (λ (e t)
#;(if (stx-pair? t)
(syntax-parse t
[(τ-expander . args) #`(#,e #'args)])
e)
(syntax-parse t
[(τ-expander . args) #`(#,e args)]
[_ e]))
@ -298,44 +288,37 @@
(assign-type #'tv #'k)
#'ok #:tag '#,tag))] ...)
(λ (x ...)
(let-syntax ([x (syntax-parser [i:id
; #:when (or (not (and (identifier? #'τ) (free-identifier=? #'x #'τ)))
; (printf "~a has type = itself\n" #'i))
; #:when (or (not (get-expected-type #'i))
; (printf "expected type of ~a: ~a\n"
; #'i (and (get-expected-type #'i)
; (syntax->datum (get-expected-type #'i)))))
; #:when (or (not (get-expected-type #'i))
; (printf "assigned type of ~a: ~a\n"
; (syntax->datum #'i) (syntax->datum #'τ)))
(if (and (identifier? #'τ) (free-identifier=? #'x #'τ))
(if (get-expected-type #'i)
(add-env (assign-type #'x (get-expected-type #'i)) #`((x #,(get-expected-type #'i))))
(raise (exn:fail:type:infer
(format "~a (~a:~a): could not infer type of ~a; add annotation(s)"
(syntax-source #'x) (syntax-line #'x) (syntax-column #'x)
(syntax->datum #'x))
(current-continuation-marks))))
(assign-type #'x #'τ))]
[(o . rst) ; handle if x used in fn position
#:fail-when (and (identifier? #'τ) (free-identifier=? #'x #'τ))
(raise (exn:fail:type:infer
(format "~a (~a:~a): could not infer type of function ~a; add annotation(s)"
(syntax-source #'o) (syntax-line #'o) (syntax-column #'o)
(syntax->datum #'o))
(current-continuation-marks)))
#:with app (datum->syntax #'o '#%app)
#`(app #,(assign-type #'x #'τ) . rst)]
#;[(_ . rst) #`(#,(assign-type #'x #'τ) . rst)])
#;(make-rename-transformer (assign-type #'x #'τ))] ...)
(let-syntax
([x
(syntax-parser
[i:id
(if (and (identifier? #'τ) (free-identifier=? #'x #'τ))
(if (get-expected-type #'i)
(add-env
(assign-type #'x (get-expected-type #'i))
#`((x #,(get-expected-type #'i))))
(raise
(exn:fail:type:infer
(format "~a (~a:~a): could not infer type of ~a; add annotation(s)"
(syntax-source #'x) (syntax-line #'x) (syntax-column #'x)
(syntax->datum #'x))
(current-continuation-marks))))
(assign-type #'x #'τ))]
[(o . rst) ; handle if x used in fn position
#:fail-when (and (identifier? #'τ) (free-identifier=? #'x #'τ))
(raise (exn:fail:type:infer
(format "~a (~a:~a): could not infer type of function ~a; add annotation(s)"
(syntax-source #'o) (syntax-line #'o) (syntax-column #'o)
(syntax->datum #'o))
(current-continuation-marks)))
#:with app (datum->syntax #'o '#%app)
#`(app #,(assign-type #'x #'τ) . rst)]
#;[(_ . rst) #`(#,(assign-type #'x #'τ) . rst)])
#;(make-rename-transformer (assign-type #'x #'τ))] ...)
(#%expression e) ... void)))))
(list #'tvs+ #'xs+ #'(e+ ...)
(stx-map ; need this check when combining #%type and kinds
(λ (t) (or (false? t)
; TODO: why does this happen?
; happens when propagating 'env up in λ
#;(and (pair? t)
(syntax-local-introduce (car t)))
(syntax-local-introduce t)))
(stx-map typeof #'(e+ ...))))]
[([x τ] ...) (infer es #:ctx #'([x : τ] ...) #:tvctx tvctx)]))
@ -433,13 +416,7 @@
((~literal #%plain-lambda) bvs
((~literal #%expression) ((~literal quote) extra-info-macro)) . tys))
(expand/df #'(extra-info-macro . tys))]
[_ #f]))
(define (get-tyargs ty)
(syntax-parse ty
[((~literal #%plain-app) internal-id
((~literal #%plain-lambda) bvs
xtra-info . rst))
#'rst])))
[_ #f])))
(define-syntax define-basic-checked-id-stx
@ -488,17 +465,14 @@
(~optional
(~seq #:arity op n:exact-nonnegative-integer)
#:defaults ([op #'=] [n #'1]))
(~optional
(~seq #:bvs (~and (~parse has-bvs? #'#t) bvs-op) bvs-n:exact-nonnegative-integer)
(~optional (~seq #:bvs (~and (~parse has-bvs? #'#t) bvs-op)
bvs-n:exact-nonnegative-integer)
#:defaults ([bvs-op #'=][bvs-n #'0]))
(~optional (~seq #:arr (~and (~parse has-annotations? #'#t) tycon))
#:defaults ([tycon #'void]))
#;(~optional (~seq #:extra-info extra-bvs extra-info)
#:defaults ([extra-bvs #'()]
[extra-info #'void]))
(~optional (~seq #:extra-info extra-info) #:defaults ([extra-info #'void]))
(~optional (~and #:no-provide (~parse no-provide? #'#t)))
)
(~optional (~seq #:extra-info extra-info)
#:defaults ([extra-info #'void]))
(~optional (~and #:no-provide (~parse no-provide? #'#t))))
#:with #%kind (format-id #'kind "#%~a" #'kind)
#:with τ-internal (generate-temporary #'τ)
#:with τ? (mk-? #'τ)
@ -549,8 +523,6 @@
(define (τ? t)
(and (stx-pair? t)
(syntax-parse t
#;[((~literal #%plain-lambda) bvs ((~literal #%plain-app) (~literal τ-internal) . _))
#t]
[((~literal #%plain-app) (~literal τ-internal) . _)
#t]
[_ #f]))))
@ -581,10 +553,6 @@
#:with k_result (if #,(attribute has-annotations?)
#'(tycon k_arg (... ...))
#'#%kind)
;; #:with extra-info-inst
;; (if (stx-null? #'extra-bvs)
;; #'extra-info
;; (substs #'τs- #'extra-bvs #'extra-info))
(add-orig
(assign-type
(syntax/loc stx
@ -720,54 +688,4 @@
[_ e]))
(define (substs τs xs e [cmp bound-identifier=?])
(stx-fold (lambda (ty x res) (subst ty x res cmp)) e τs xs))
;; subst-expr:
;; - like subst except the target can be any stx, rather than just an id
;; - used for implementing polymorphic recursive types
(define (stx-lam? s)
(syntax-parse s
[((~literal #%plain-lambda) . rst) #t] [_ #f]))
(define (stx-lam=? s1 s2)
(syntax-parse (list s1 s2)
[(((~literal #%plain-lambda) xs . bs1)
((~literal #%plain-lambda) ys . bs2))
#:with zs (generate-temporaries #'xs)
(and (stx-length=? #'xs #'ys)
(stx=? (substs #'zs #'xs #'bs1)
(substs #'zs #'ys #'bs2)))]))
(define (stx=? s1 s2)
(or (and (identifier? s1) (identifier? s2) (free-identifier=? s1 s2))
(and (stx-null? s1) (stx-null? s2))
(and (stx-lam? s1) (stx-lam? s2) (stx-lam=? s1 s2))
(and (stx-pair? s1) (stx-pair? s2) (stx-length=? s1 s2)
(stx-andmap stx=? s1 s2))))
;; subst e1 for e2 in e3
(define (subst-expr e1 e2 e3)
(cond
[(stx=? e2 e3) e1]
[(identifier? e3) e3]
[else ; stx-pair
(with-syntax ([result (stx-map (lambda (e) (subst-expr e1 e2 e)) e3)])
(syntax-track-origin #'result e3 #'here))]))
(define (subst-exprs τs xs e)
(stx-fold subst-expr e τs xs))
;; subst-special:
;; - used for unfolding polymorphic recursive type
;; subst ty1 for x in ty2
;; where ty1 is an applied type constructor type
;; x is a placeholder for an applied tycons type in ty2
;; - subst special first replaces the args of ty1 with that of x
;; before replacing applications of tycons x with this modified ty1
(define (subst-special ty1 x ty2)
(cond
[(identifier? ty2) ty2]
[(syntax-parse ty2 [((~literal #%plain-app) tycons:id . _) (free-identifier=? #'tycons x)] [_ #f])
(syntax-parse ty2
[((~literal #%plain-app) tycons:id . newargs)
; #:with oldargs (get-tyargs ty1)
(subst-exprs #'newargs (get-tyargs ty1) ty1)])]
[else ; stx-pair
(with-syntax ([result (stx-map (lambda (e) (subst-special ty1 x e)) ty2)])
(syntax-track-origin #'result ty2 #'here))]))
)
(stx-fold (lambda (ty x res) (subst ty x res cmp)) e τs xs)))