typed: improvements and bug fixes for eliding type annotations

This commit is contained in:
Sam Caldwell 2022-05-04 21:00:31 -04:00
parent b9f655766f
commit c9b25df034
5 changed files with 81 additions and 26 deletions

View File

@ -531,10 +531,12 @@
;; The input types are already expanded/normalized
;; avoids namespace module mismatch issue in some cases
(define-for-syntax (mk-U- tys)
(define tys- (prune+sort tys))
(if (= 1 (stx-length tys-))
(stx-car tys-)
(mk-U*- tys-)))
(syntax-parse tys
[((~or (~U* ty1- ...) ty2-) ...)
(define tys- (prune+sort #'(ty1- ... ... ty2- ...)))
(if (= 1 (stx-length tys-))
(stx-car tys-)
(mk-U*- tys-))]))
(define-syntax (U stx)
(syntax-parse stx
@ -546,6 +548,10 @@
(stx-car #'tys-)
(syntax/loc stx (U* . tys-)))]))
;; Listof Type -> Type
(define-for-syntax (mk-U tys)
(type-eval #`(U #,@tys)))
(define-simple-macro (→fn ty-in ... ty-out)
(→+ ty-in ... (Computation (Value ty-out)
(Endpoints)
@ -649,12 +655,14 @@
;; e.g. book-club -> BookClubT
(begin-for-syntax
;; Identifier -> Identifier
;; Identifier -> (list Identifier Identifier)
(define (camel-case-T nm)
(define nm/s (symbol->string (syntax-e nm)))
(define nm/camel (string-append* (map string-titlecase (string-split nm/s "-"))))
(format-id nm "~aT" nm/camel))
(list (format-id nm "~aT" nm/camel)
(format-id nm "~a" nm/camel)))
;; (Parameterof (Identifier -> (list Identifier Identifier)))
(define current-type-constructor-convention
(make-parameter camel-case-T)))
@ -691,11 +699,16 @@
#:type-constructor TyCons
clause ...)]
[(_ (Cons:id slot:slot-decl ...) clause ...)
#:with TyCons ((current-type-constructor-convention) #'Cons)
(syntax/loc stx
#:with (TyCons Ty) ((current-type-constructor-convention) #'Cons)
(define provided-tys (attribute slot.type))
(define all-provided? (andmap values provided-tys))
(quasisyntax/loc stx
(define-constructor (Cons slot ...)
#:type-constructor TyCons
clause ...))]))
clause ...
#,@(if all-provided?
#'(#:with Ty (TyCons slot.type ...))
#'())))]))
(begin-for-syntax
(define ((mk-type-params-fetcher TypeCons) ty)
@ -803,11 +816,13 @@
;; TODO: this implementation shares a lot with that of define-constructor
(define-syntax (require-struct stx)
(syntax-parse stx
[(_ ucons:id #:as ty-cons:id #:from lib
[(_ ucons:id
(~optional (~seq #:as ty-cons:id))
#:from lib
(~optional (~seq slot:slot-decl ...))
(~optional (~and omit-accs #:omit-accs)))
;; TBH I'm not sure why I don't need to SLIAB TypeCons and Cons-
#:with TypeCons #'ty-cons
#:with (TypeCons Ty) #`(~? (ty-cons ty-cons) #,((current-type-constructor-convention) #'ucons))
#:with MakeTypeCons (format-id #'TypeCons "make-~a" #'TypeCons)
#:with GetTypeParams (format-id #'TypeCons "get-~a-type-params" #'TypeCons)
#:with TypeConsExpander (format-id #'TypeCons "~~~a" #'TypeCons)
@ -858,11 +873,10 @@
#'accs/rev
arity
#,(attribute omit-accs)
(list #'field-ty? ...)
#'field-tys
#'field-accs?
#;(list #'field-acc ...)))
(finish-type-defs ucons TypeCons)
))]))
#'field-accs?))
(finish-type-defs ucons TypeCons Ty)))]))
;; This is so that the arity of the struct can be included in the generated typedef
(define-for-syntax ((finish-require-struct-typedef lib
@ -875,14 +889,23 @@
accs/rev
arity
omit-accs?
field-tys
field-tys?
field-tys-nm
field-accs?)
stx)
(syntax-parse stx
[(_ ucons:id TypeCons:id)
[(_ ucons:id TypeCons:id Ty:id)
#:do [(define all-types-given? (and (equal? arity (length field-tys?))
(andmap values field-tys?)))
(define define-ty-alias?
(and all-types-given?
(not (bound-identifier=? #'TypeCons #'Ty))))]
#:with field-accs #`(if (empty? #,field-accs?)
(cleanup-accs #'ucons #,accs/rev)
(format-all #'ucons #,field-accs?))
#:with field-tys (if all-types-given?
field-tys-nm
#`(list #,@(make-list arity #f)))
(quasisyntax/loc #'ucons
(begin-
(define-for-syntax (#,TypeConsExtraInfo stx)
@ -900,13 +923,15 @@
'#,type-tag
#'TypeCons
field-accs
#,field-tys))
field-tys))
#,(unless omit-accs?
(quasisyntax/loc #'ucons
(begin-
(define-syntax mk-struct-accs
(define-struct-accs #,accs/rev #,field-accs? #'TypeCons #'#,lib))
(mk-struct-accs ucons))))))]))
(mk-struct-accs ucons))))
#,(when define-ty-alias?
#`(define-type-alias Ty (TypeCons #,@field-tys?)))))]))
(begin-for-syntax
(define-syntax ~constructor-extra-info
@ -1005,7 +1030,7 @@
(pattern [#:struct Cons:id
(~optional (~seq slot:slot-decl ...))
(~optional (~and omit-accs #:omit-accs))]
#:attr TyCons ((current-type-constructor-convention) #'Cons)))
#:attr TyCons #f))
)
;; Import and ascribe a type from an untyped module
@ -1021,7 +1046,8 @@
#:with (name- ...) (format-ids "~a-" #'(name ...))
(syntax/loc stx
(begin-
(require-struct struct-clause.Cons #:as struct-clause.TyCons
(require-struct struct-clause.Cons
(~? (~@ #:as struct-clause.TyCons))
#:from lib
(~? (~@ struct-clause.slot ...))
(~? struct-clause.omit-accs)) ...

View File

@ -372,8 +372,10 @@
identity))
(define-typed-syntax spawn
;; TODO - do the lack of #:cut-s cause bad error messages here?
[(spawn τ-c:type s)
[(spawn tc s)
;; this setup is to avoid re-expansion of the tc position :<
#:cut
#:with τ-c:type #'tc
#:fail-unless (flat-type? #'τ-c.norm) "Communication type must be first-order"
;; TODO: check that each τ-f is a Role
#:mode (communication-type-mode #'τ-c.norm)
@ -401,9 +403,11 @@
[(spawn s)
#:do [(define τc (current-communication-type))]
#:when τc
#:cut
----------------------------------------
[ (spawn #,τc s)]]
[(spawn s)
#:cut
[ (block s) s- ( ν-ep (~effs)) ( ν-s (~effs)) ( ν-f (~effs τ-f ...))]
;; TODO: s shouldn't refer to facets or fields!
#:fail-unless (and (stx-andmap Role? #'(τ-f ...))
@ -412,7 +416,8 @@
#:with (τ-i τ-o τ-i/i τ-o/i τ-a) (analyze-roles #'(τ-f ...))
#:fail-unless (project-safe? ( (strip-? #'τ-o/i) #'τ-o/i) #'τ-i/i)
(string-append "Not prepared to handle internal events:\n" (make-actor-error-message #'τ-i/i #'τ-o/i #'τ-o/i))
#:with τ-i/o (pattern-matching-assertions #'τ-i)
;; if there are Discards in pattern types, this will take more specific instances from other patterns
#:with τ-i/o (replace-bind-and-discard-with-★ (instantiate-pattern-type #'τ-i))
#:with (~U* (~AnyActor τ-c/spawned) ...) #'τ-a
#:with τ-c/this-actor (type-eval #'(U τ-i/o τ-o))
#:with τ-c/final (type-eval #'(U τ-c/this-actor τ-c/spawned ...))
@ -484,7 +489,7 @@
#:with τ-ds-i (strip-inbound #'τ-c.norm)
#:with τ-ds-o (strip-outbound #'τ-c.norm)
#:with τ-relay (relay-interests #'τ-c.norm)
#:with τ-ds-act (mk-Actor- (list (mk-U*- #'(τ-ds-i τ-ds-o τ-relay))))
#:with τ-ds-act (mk-Actor- (list (mk-U- #'(τ-ds-i τ-ds-o τ-relay))))
-----------------------------------------------------------------------------------
[ (syndicate:dataspace s- ...) ( : ★/t)
( ν-s (τ-ds-act))]]
@ -702,8 +707,9 @@
;; n.b. this is a blocking operation, so an actor that uses this internally
;; won't necessarily terminate.
(define-typed-syntax run-ground-dataspace
;; TODO : this has the same problem with re-expansion of what's in the τ-c position as spawn
[(run-ground-dataspace τ-c:type s ...)
;;#:fail-unless (flat-type? #'τ-c.norm) "Communication type must be first-order"
#:fail-unless (flat-type? #'τ-c.norm) "Communication type must be first-order"
#:mode (communication-type-mode #'τ-c.norm)
[
[ s s- ( : t1)] ...

View File

@ -10,3 +10,13 @@
#:with HungryHippos (HungryHipposT Int String))
(check-type (hungry-hippos 12 "massive") : HungryHippos)
(define-constructor* (doggy [color : String] [weight : Int]))
(check-type (doggy "black" 60) : (DoggyT String Int))
(check-type (doggy "brown" 45) : Doggy)
(define-constructor* (leaf))
(check-type (leaf) : (LeafT))
(check-type (leaf) : Leaf)

View File

@ -8,5 +8,14 @@
(check-type (donkey 5 #t)
: (DonkeyT Int Bool))
(check-type (donkey 5 #t)
: Donkey)
(check-type (donkey-grey? (donkey 5 #t))
: Bool)
(require/typed "struct-provider.rkt"
[#:struct pot])
(check-type (pot) : (PotT))
(check-type (pot) : Pot)

View File

@ -3,3 +3,7 @@
(struct donkey (weight stubborn?) #:transparent)
(provide (struct-out donkey))
(struct pot () #:transparent)
(provide (struct-out pot))