diff --git a/typed-racket-lib/typed-racket/base-env/base-contracted.rkt b/typed-racket-lib/typed-racket/base-env/base-contracted.rkt index e823f70a9..a3fa613c4 100644 --- a/typed-racket-lib/typed-racket/base-env/base-contracted.rkt +++ b/typed-racket-lib/typed-racket/base-env/base-contracted.rkt @@ -31,6 +31,7 @@ (begin-for-syntax (module* #%type-decl #f (#%plain-module-begin + (#%declare #:empty-namespace) (require typed-racket/env/global-env typed-racket/types/abbrev typed-racket/rep/type-rep) @@ -43,3 +44,9 @@ ;; ;; Also, this type works better with inference. (-> (make-Prompt-Tagof Univ (-> Univ ManyUniv))))))) + +;; we also have to manually add these submodules which extra-env-lang.rkt would do for us +(begin-for-syntax + (module* #%contract-defs-names #f (#%plain-module-begin (#%declare #:empty-namespace)))) +(module* #%contract-defs #f (#%plain-module-begin (#%declare #:empty-namespace))) + diff --git a/typed-racket-lib/typed-racket/base-env/base-types.rkt b/typed-racket-lib/typed-racket/base-env/base-types.rkt index 19c28465b..ce435e246 100644 --- a/typed-racket-lib/typed-racket/base-env/base-types.rkt +++ b/typed-racket-lib/typed-racket/base-env/base-types.rkt @@ -93,7 +93,7 @@ [Void -Void] [Undefined -Undefined] ; initial value of letrec bindings -;; [Unsafe-Undefined -Unsafe-Undefined] ; not clear that it makes sense to export this +[Unsafe-Undefined -Unsafe-Undefined] ; not clear that it makes sense to export this [Boolean -Boolean] [Symbol -Symbol] [String -String] diff --git a/typed-racket-lib/typed-racket/base-env/extra-env-lang.rkt b/typed-racket-lib/typed-racket/base-env/extra-env-lang.rkt index 571eb6b55..44c76a593 100644 --- a/typed-racket-lib/typed-racket/base-env/extra-env-lang.rkt +++ b/typed-racket-lib/typed-racket/base-env/extra-env-lang.rkt @@ -78,8 +78,20 @@ (define-syntax (-#%module-begin stx) (syntax-parse stx + [(mb #:contract-defs e ...) + #'(#%plain-module-begin + (require (for-syntax typed-racket/env/env-req)) + e ... + ;; need to register this module + (begin-for-syntax (add-mod! (variable-reference->module-path-index + (#%variable-reference)))))] [(mb e ...) #'(#%plain-module-begin + ;; auto-generate these modules unless they are explicitly provided + ;; use #%plain-module-begin to avoid adding add-mod! calls in them + (begin-for-syntax (module* #%contract-defs-names #f + (#%plain-module-begin (#%declare #:empty-namespace)))) + (module* #%contract-defs #f (#%plain-module-begin (#%declare #:empty-namespace))) (require (for-syntax typed-racket/env/env-req)) e ... ;; need to register this module diff --git a/typed-racket-lib/typed-racket/base-env/prims.rkt b/typed-racket-lib/typed-racket/base-env/prims.rkt index 14a9afdd0..071364710 100644 --- a/typed-racket-lib/typed-racket/base-env/prims.rkt +++ b/typed-racket-lib/typed-racket/base-env/prims.rkt @@ -141,6 +141,7 @@ the typed racket language. ;; contracted bindings in typed modules) values that are contracted ;; for _all_ typed programs. (module+ #%contract-defs + (#%declare #:empty-namespace) (require "base-contracted.rkt") (provide (all-from-out "base-contracted.rkt"))) diff --git a/typed-racket-lib/typed-racket/env/env-req.rkt b/typed-racket-lib/typed-racket/env/env-req.rkt index 224dad0a1..36f763339 100644 --- a/typed-racket-lib/typed-racket/env/env-req.rkt +++ b/typed-racket-lib/typed-racket/env/env-req.rkt @@ -1,8 +1,18 @@ #lang racket/base +(require syntax/modresolve syntax/modcollapse (for-template racket/base) racket/match) (define to-require null) (define (add-mod! m) (set! to-require (cons m to-require))) +;; produce code for all the requires we need to load types +(define (get-requires) + (for/list ([m (in-list to-require)] + #:when m) + (define path (->mp m '#%type-decl)) + #`(#%require (only #,(adjust path))))) + +;; dynamically do all of the above requires +;; populates the type name tables (define (do-requires [ns (current-namespace)]) (parameterize ([current-namespace ns]) (for ([m (in-list to-require)] @@ -10,4 +20,35 @@ (dynamic-require (module-path-index-join '(submod "." #%type-decl) m) #f)))) -(provide add-mod! do-requires) +;; adjust: require-spec -> require-spec +;; rewrite a spec that works in a module M to one that works in a submodule of M +(define (adjust p) + (match p + [`(submod "." ,r0 ,rest ...) + `(submod ".." ,r0 . ,rest)] + [`(submod ,(and up (or "." "..")) ,rest ...) + `(submod ".." ,up . ,rest)] + [_ p])) + +;; ->mp : module-path-index? symbol? -> module-path-index? +;; combine module-path-index with a submodule, producing an sexp we can manipulate +(define (->mp mpi submod) + (collapse-module-path-index (module-path-index-join `(submod "." ,submod) mpi))) + +;; generate code to require the modules that have the definitions of the contracts +(define (get-contract-requires) + (for/list ([m (in-list to-require)] #:when m) + #`(#%require (only #,(adjust (->mp m '#%contract-defs)))))) + +;; dynamically do the above requires +;; populates the table that tells us what names get us what contracts +(define (do-contract-requires [ns (current-namespace)]) + (parameterize ([current-namespace ns]) + (for ([m (in-list to-require)] + #:when m) + (dynamic-require + (module-path-index-join '(submod "." #%contract-defs-names) m) + #f)))) + +(provide add-mod! do-requires get-requires + get-contract-requires do-contract-requires) diff --git a/typed-racket-lib/typed-racket/env/init-envs.rkt b/typed-racket-lib/typed-racket/env/init-envs.rkt index b720e8db3..c2819a514 100644 --- a/typed-racket-lib/typed-racket/env/init-envs.rkt +++ b/typed-racket-lib/typed-racket/env/init-envs.rkt @@ -61,13 +61,15 @@ ;; Compute for a given type how many times each type inside of it ;; is referenced (define (compute-popularity x) + (define v (hash-ref pop-table x 0)) (when (Type? x) - (hash-update! pop-table x add1 0)) - (when (Rep? x) + (hash-set! pop-table x (add1 v))) + (when (and (Rep? x) (zero? v)) (Rep-for-each x compute-popularity))) +;; types that are popular (referenced more than once) get their own definition (define (popular? ty) - (> (hash-ref pop-table ty 0) 5)) + (> (hash-ref pop-table ty 0) 1)) ;; Type -> S-Exp ;; Convert a type to an s-expression to evaluate @@ -81,8 +83,8 @@ ;; predefined table [(and (not (identifier? *res)) (popular? ty)) - (define id (gensym)) - (enqueue! type-definitions #`(define #,id #,*res)) + (define id (car (generate-temporaries '(g)))) + (enqueue! type-definitions #`(define/decl #,id #,*res)) id] [else *res])) (hash-set! type-cache ty res) @@ -168,6 +170,15 @@ (TrueProp:)) (Empty:))))))) `(simple-> (list ,@(map type->sexp dom)) ,(type->sexp t))] + [(Fun: (list (Arrow: dom #f '() + (Values: + (list + (Result: t + (PropSet: (TrueProp:) + (TrueProp:)) + (Empty:)) + ...))))) + `(simple->values (list ,@(map type->sexp dom)) (list ,@(map type->sexp t)))] [(Fun: (list (Arrow: dom #f'() (Values: (list @@ -197,7 +208,7 @@ (match-define (Arrow: fdoms _ kws rng) (first arrs)) (match-define (Arrow: ldoms rst _ _) (last arrs)) (define opts (drop ldoms (length fdoms))) - `(opt-fn + `(opt-fn* (list ,@(map type->sexp fdoms)) (list ,@(map type->sexp opts)) ,(type->sexp rng) @@ -278,10 +289,10 @@ `(quote ,n))) ,(type->sexp b))] [(PolyRow-names: ns c b) - `(make-PolyRow (list ,@(for/list ([n (in-list ns)]) - `(quote ,n))) - (quote ,c) - ,(type->sexp b))] + `(make-PolyRow-simple (list ,@(for/list ([n (in-list ns)]) + `(quote ,n))) + (quote ,c) + ,(type->sexp b))] [(Row: inits fields methods augments init-rest) `(make-Row (list ,@(convert-row-clause inits #t)) (list ,@(convert-row-clause fields)) @@ -295,6 +306,7 @@ (list ,@(convert-row-clause methods)) (list ,@(convert-row-clause augments)) ,(and init-rest (type->sexp init-rest)))] + [(Instance: (Name: n 0 #f)) `(simple-inst (quote-syntax ,n))] [(Instance: ty) `(make-Instance ,(type->sexp ty))] [(Signature: name extends mapping) (define (serialize-mapping m) @@ -312,15 +324,9 @@ (list ,@(map type->sexp exports)) (list ,@(map type->sexp init-depends)) ,(type->sexp result))] - [(Arrow: dom #f '() - (Values: (list (Result: t (PropSet: (TrueProp:) - (TrueProp:)) - (Empty:))))) - `(-Arrow (list ,@(map type->sexp dom)) - ,(type->sexp t))] [(Arrow: dom #f '() rng) - `(-Arrow (list ,@(map type->sexp dom)) - ,(type->sexp rng))] + `(simple-arrow (list ,@(map type->sexp dom)) + ,(type->sexp rng))] [(Arrow: dom rest kws rng) `(make-Arrow (list ,@(map type->sexp dom)) diff --git a/typed-racket-lib/typed-racket/private/type-contract.rkt b/typed-racket-lib/typed-racket/private/type-contract.rkt index 116cccfc5..fdf2b70b7 100644 --- a/typed-racket-lib/typed-racket/private/type-contract.rkt +++ b/typed-racket-lib/typed-racket/private/type-contract.rkt @@ -2,12 +2,14 @@ ;; Contract generation for Typed Racket + + (require "../utils/utils.rkt" syntax/parse (rep type-rep prop-rep object-rep fme-utils) (utils tc-utils prefab identifier) - (env type-name-env row-constraint-env) + (env type-name-env row-constraint-env env-req) (rep core-rep rep-utils free-ids type-mask values-rep base-types numeric-base-types) (types resolve utils printer match-expanders union subtype) @@ -27,13 +29,15 @@ (provide (c:contract-out - [type->static-contract - (c:parametric->/c (a) ((Type? (c:-> #:reason (c:or/c #f string?) a)) - (#:typed-side boolean?) . c:->* . (c:or/c a static-contract?)))])) + [type->contract c:any/c] + [type->static-contract + (c:parametric->/c (a) ((Type? (c:-> #:reason (c:or/c #f string?) a)) + (#:typed-side boolean?) . c:->* . (c:or/c a static-contract?)))])) (provide change-contract-fixups change-provide-fixups any-wrap/sc + from-typed? extra-requires include-extra-requires?) @@ -163,7 +167,8 @@ (and (identifier? ctc-stx) (let ([match? (assoc ctc-stx (hash-values cache) free-identifier=?)]) (and match? - (should-inline-contract? (cdr match?)) + (or (should-inline-contract? (cdr match?)) + (function-contract? (cdr match?))) (cdr match?))))) ;; The below requires are needed since they provide identifiers that @@ -172,20 +177,26 @@ ;; TODO: It would be better to have individual contracts specify which ;; modules should be required, but for now this is just all of them. (define extra-requires - #'(require - (submod typed-racket/private/type-contract predicates) - typed-racket/utils/utils - (for-syntax typed-racket/utils/utils) - typed-racket/utils/any-wrap typed-racket/utils/struct-type-c - typed-racket/utils/prefab-c - typed-racket/utils/opaque-object - typed-racket/utils/evt-contract - typed-racket/utils/hash-contract - typed-racket/utils/sealing-contract - typed-racket/utils/promise-not-name-contract - typed-racket/utils/simple-result-arrow - racket/sequence - racket/contract/parametric)) + #`(require + ;; some built-in types that aren't available in `racket/base` + (submod typed-racket/private/type-contract predicates) + ;; a table of contracts that are defined in other modules so they aren't + ;; repeated + (submod typed-racket/static-contracts/instantiate predefined-contracts) + ;; utility functions + typed-racket/utils/utils + (for-syntax typed-racket/utils/utils) + racket/sequence + ;; contract combinators + typed-racket/utils/any-wrap typed-racket/utils/struct-type-c + typed-racket/utils/prefab-c + typed-racket/utils/opaque-object + typed-racket/utils/evt-contract + typed-racket/utils/hash-contract + typed-racket/utils/sealing-contract + typed-racket/utils/promise-not-name-contract + typed-racket/utils/simple-result-arrow + racket/contract/parametric)) ;; Should the above requires be included in the output? ;; This box is only used for contracts generated for `require/typed` @@ -314,7 +325,7 @@ ;; Macro to simplify (and avoid reindentation) of the match below ;; ;; The sc-cache hashtable is used to memoize static contracts. The keys are -;; a pair of the Type-seq number for a type and 'untyped or 'typed +;; a pair of the type and 'untyped or 'typed (define-syntax (cached-match stx) (syntax-case stx () [(_ sc-cache type-expr typed-side-expr match-clause ...) @@ -401,6 +412,9 @@ sc)) (cached-match sc-cache type typed-side + [(app (lambda (t) (hash-ref predef-contracts (cons t typed-side) #f)) + (? values con-id)) + (impersonator/sc (syntax-local-introduce con-id))] ;; Applications of implicit recursive type aliases ;; ;; We special case this rather than just resorting to standard @@ -1008,6 +1022,8 @@ (define extflnonnegative? (lambda (x) (extfl>= x 0.0t0))) (define extflnonpositive? (lambda (x) (extfl<= x 0.0t0)))) +(require (submod "../static-contracts/instantiate.rkt" predefined-contracts)) + (module numeric-contracts racket/base (require "../utils/utils.rkt" diff --git a/typed-racket-lib/typed-racket/static-contracts/instantiate.rkt b/typed-racket-lib/typed-racket/static-contracts/instantiate.rkt index c5c1173cc..f03ba3d3e 100644 --- a/typed-racket-lib/typed-racket/static-contracts/instantiate.rkt +++ b/typed-racket-lib/typed-racket/static-contracts/instantiate.rkt @@ -32,6 +32,7 @@ (parametric->/c (a) ((static-contract? (-> #:reason (or/c #f string?) a)) (contract-kind? #:cache hash? #:recursive-kinds (or/c hash? #f)) . ->* . (or/c a (list/c (listof syntax?) syntax?))))] + [function-contract? (-> syntax? boolean?)] [should-inline-contract? (-> syntax? boolean?)]) ;; Providing these so that tests can work directly with them. @@ -159,6 +160,8 @@ ;; calls, which helps for inlining (define (recur sc [top-level? #f]) (cond [(and cache (hash-ref cache sc #f)) => car] + ;; fixme: check for kind + [(hash-ref predef-contracts sc #f)] [(arr/sc? sc) (make-contract sc)] [(or (parametric->/sc? sc) (sealing->/sc? sc)) (match-define (or (parametric->/sc: vars _) @@ -173,14 +176,16 @@ [(static-contract-may-contain-free-ids?) (make-contract sc)] [else (define ctc (make-contract sc)) - (cond [(and ;; when a contract benefits from inlining - ;; (e.g., ->) and this contract appears - ;; directly in a define-module-boundary-contract - ;; position (i.e, top-level? is #t) then - ;; don't generate a new identifier for it - (or (not (should-inline-contract? ctc)) - (not top-level?)) - cache) + (cond [(and + cache + ;; when a contract benefits from inlining + ;; (e.g., ->) and this contract appears + ;; directly in a define-module-boundary-contract + ;; position (i.e, top-level? is #t) then + ;; don't generate a new identifier for it + (not (should-inline-contract? ctc)) + (or (not (function-contract? ctc)) + (not top-level?))) (define fresh-id (generate-temporary)) (hash-set! cache sc (cons fresh-id ctc)) (set! sc-queue (cons sc sc-queue)) @@ -232,16 +237,37 @@ #`(define #,id #,ctc))) ctc)) +(module predefined-contracts racket/base + ;; this table maps (cons Type? typed-side?) -> (cons identifier? kind?) + ;; where the identifier can be used instead of generating a contract for the type + (define predef-contracts (make-hash)) + (define-syntax-rule (define/contract-decl i ctc sc) + (begin (hash-set! predef-contracts sc #'i) + (define i ctc))) + (provide predef-contracts define/contract-decl)) + +(require (submod "." predefined-contracts) + (for-template (submod "." predefined-contracts))) + ;; Determine whether the given contract syntax should be inlined or not. (define (should-inline-contract? stx) - (or - ;; no need to generate an extra def for things that are already identifiers - (identifier? stx) - ;; ->* are handled specially by the contract system - (let ([sexp (syntax-e stx)]) - (and (pair? sexp) - (or (free-identifier=? (car sexp) #'->) - (free-identifier=? (car sexp) #'->*)))))) + (syntax-case stx (quote) + ;; no need to generate an extra def for things that are already identifiers + [i (identifier? #'i) #t] + [(quote i) (or (identifier? #'i) + (boolean? (syntax-e #'i)) + (number? (syntax-e #'i))) + #t] + [_ #f])) + +(define (function-contract? stx) + (syntax-case stx () + [(arrow . _) + (and (identifier? #'arrow) + (or (free-identifier=? #'arrow #'->) + (free-identifier=? #'arrow #'->*))) + #t] + [_ #f])) ;; determine if a given name is free in the sc (define (name-free-in? name sc) diff --git a/typed-racket-lib/typed-racket/static-contracts/structures.rkt b/typed-racket-lib/typed-racket/static-contracts/structures.rkt index 59a6dbb93..9ad195b85 100644 --- a/typed-racket-lib/typed-racket/static-contracts/structures.rkt +++ b/typed-racket-lib/typed-racket/static-contracts/structures.rkt @@ -106,8 +106,13 @@ ;; Returns the kind of contract that this represents ;; Returns #f if it is not a terminal contract [sc-terminal-kind sc] + ;; sc-type: static-contract? -> (or/c #f Type?) + ;; What type was this static contract generated from + ;; Produces #f if it wasn't directly from a type, or if not known + [sc-type sc] #:fallbacks - [(define (sc-terminal-kind v) #f)]) + [(define (sc-terminal-kind v) #f) + (define (sc-type v) #f)]) ;; Super struct of static contracts (struct static-contract () @@ -171,4 +176,5 @@ [sc->constraints (static-contract? (static-contract? . -> . contract-restrict?) . -> . contract-restrict?)] [sc-terminal-kind (static-contract? . -> . (or/c #f contract-kind?))] + [sc-type (static-contract? . -> . any/c)] [sc? predicate/c]) diff --git a/typed-racket-lib/typed-racket/typecheck/tc-toplevel.rkt b/typed-racket-lib/typed-racket/typecheck/tc-toplevel.rkt index 5b44fc542..fc4334dd0 100644 --- a/typed-racket-lib/typed-racket/typecheck/tc-toplevel.rkt +++ b/typed-racket-lib/typed-racket/typecheck/tc-toplevel.rkt @@ -479,6 +479,8 @@ (define/with-syntax (new-defs ...) defs) (define/with-syntax (new-export-defs ...) export-defs) (define/with-syntax (new-provs ...) provs) + ;; initialize the contract name tables before we do contract generation + (do-contract-requires) (values #`(begin ;; This syntax-time submodule records all the types for all @@ -498,6 +500,7 @@ typed-racket/env/global-env typed-racket/env/type-alias-env typed-racket/types/struct-table typed-racket/types/abbrev (rename-in racket/private/sort [sort raw-sort])) + #,@(get-requires) #,@(make-env-init-codes) #,@(for/list ([a (in-list aliases)]) (match-define (list from to) a) @@ -523,6 +526,7 @@ ;; We need a submodule for a for-syntax use of ;; `define-runtime-module-path`: (module #%contract-defs-reference racket/base + (#%declare #:empty-namespace) (require racket/runtime-path (for-syntax racket/base)) (define-runtime-module-path-index contract-defs-submod @@ -554,8 +558,21 @@ (module* #%contract-defs #f (#%plain-module-begin (#%declare #:empty-namespace) ;; avoid binding info from here + #,@(get-contract-requires) + #,extra-requires - new-defs ...))) + new-defs ...)) + (begin-for-syntax + (module* #%contract-defs-names #f + (#%plain-module-begin + (#%declare #:empty-namespace) ;; avoid binding info from here + + ;; we need to know what types we have names for so + ;; that we can serialize them when we generate + ;; predefined contract mappings + (require (submod ".." #%type-decl)) + + )))) #`(begin ;; Now we create definitions that are actually provided ;; from the module itself. There are two levels of diff --git a/typed-racket-lib/typed-racket/types/abbrev.rkt b/typed-racket-lib/typed-racket/types/abbrev.rkt index be539b636..bdde00df7 100644 --- a/typed-racket-lib/typed-racket/types/abbrev.rkt +++ b/typed-racket-lib/typed-racket/types/abbrev.rkt @@ -42,6 +42,7 @@ (define -evt make-Evt) (define -weak-box make-Weak-Box) (define -inst make-Instance) +(define (simple-inst n) (make-Instance (make-Name n 0 #f))) (define (-prefab key . types) (make-Prefab (normalize-prefab-key key (length types)) types)) (define (-prefab-top key field-count) @@ -140,6 +141,15 @@ (define/decl -NonPosExtFlonum (Un -NegExtFlonum -ExtFlonumZero)) (define/decl -ExtFlonum (Un -NegExtFlonumNoNan -ExtFlonumNegZero -ExtFlonumPosZero -PosExtFlonumNoNan -ExtFlonumNan)) +;; these decls are for popular types, putting them here means other modules +;; don't have to define them +(define/decl ->Void (-> -Void)) +(define/decl ->Bool (-> -Boolean)) +(define/decl ->String (-> -String)) +(define/decl ->Any (-> Univ)) +(define/decl ->Integer (-> -Int)) +(define/decl Any->Void (-> Univ -Void)) + ;; Type alias names (define (-struct-name name) (make-Name name 0 #t)) @@ -177,7 +187,18 @@ #:kws kws)))))) (define-syntax-rule (->opt args ... [opt ...] res) - (opt-fn (list args ...) (list opt ...) res)) + (opt-fn* (list args ...) (list opt ...) res)) + +;; these two definitions allow shorter expansion of types by avoid the keyword expansion +(define (simple-opt-fn args opt-args result) + (opt-fn args opt-args result)) + +(define-syntax opt-fn* + (syntax-rules () + [(_ args opt-args result) + (simple-opt-fn args opt-args result)] + [(_ . args) + (opt-fn . args)])) ;; from define-new-subtype (define (-Distinction name sym ty) diff --git a/typed-racket-lib/typed-racket/types/base-abbrev.rkt b/typed-racket-lib/typed-racket/types/base-abbrev.rkt index 9965c101c..fc098ec9c 100644 --- a/typed-racket-lib/typed-racket/types/base-abbrev.rkt +++ b/typed-racket-lib/typed-racket/types/base-abbrev.rkt @@ -199,9 +199,16 @@ #:rest (make-RestDots dty 'dbound) #:props props))))])) +;; some simple function type constructors to shrink type serialization (define (simple-> doms rng) (->* doms rng)) +(define (simple-arrow doms rng) + (-Arrow doms rng)) + +(define (simple->values doms rng) + (->* doms (make-Values (map -result rng)))) + (define (->acc dom rng path #:var [var (cons 0 0)]) (define obj (-acc-path path (-id-path var))) (make-Fun @@ -334,5 +341,9 @@ (syntax-rules () [(_ (var) consts ty) (let ([var (-v var)]) - (make-PolyRow (list 'var) consts ty))])) + (make-PolyRow-simple (list 'var) consts ty))])) + +;; simplifies expansion +(define (make-PolyRow-simple v c t) + (make-PolyRow v c t)) diff --git a/typed-racket-lib/typed-racket/utils/opaque-object.rkt b/typed-racket-lib/typed-racket/utils/opaque-object.rkt index 82b5015a8..bcda92ecb 100644 --- a/typed-racket-lib/typed-racket/utils/opaque-object.rkt +++ b/typed-racket-lib/typed-racket/utils/opaque-object.rkt @@ -139,14 +139,23 @@ #:with method-names #'(list (quote name)) #:with method-ctcs #'(list ctc)))) +(define-syntax static-append + (syntax-rules (list quote null) + [(_ (list (quote e) ...) ...) (quote (e ... ...))] + [(_ (list e ...) ...) (list e ... ...)] + [(_ (list) . rest) (static-append . rest)] + [(_ null . rest) (static-append . rest)] + [(_) '()] + [(_ . e) (append . e)])) + (define-syntax (object/c-opaque stx) (syntax-parse stx [(_ ?clause:object/c-clause ...) (syntax/loc stx - (let ([names (append ?clause.method-names ...)] - [ctcs (append ?clause.method-ctcs ...)] - [fnames (append ?clause.field-names ...)] - [fctcs (append ?clause.field-ctcs ...)]) + (let ([names (static-append ?clause.method-names ...)] + [ctcs (static-append ?clause.method-ctcs ...)] + [fnames (static-append ?clause.field-names ...)] + [fctcs (static-append ?clause.field-ctcs ...)]) (base-object/c-opaque (dynamic-object/c names ctcs fnames fctcs) names ctcs fnames fctcs)))])) diff --git a/typed-racket-lib/typed-racket/utils/tc-utils.rkt b/typed-racket-lib/typed-racket/utils/tc-utils.rkt index 54ed5e6b4..cd9ba7876 100644 --- a/typed-racket-lib/typed-racket/utils/tc-utils.rkt +++ b/typed-racket-lib/typed-racket/utils/tc-utils.rkt @@ -280,7 +280,10 @@ don't depend on any other portion of the system (current-continuation-marks)))) ;; are we currently expanding in a typed module (or top-level form)? -(define typed-context? (box #f)) +(module typed-context '#%kernel + (#%provide typed-context?) + (define-values (typed-context?) (box #f))) +(require (submod "." typed-context)) ;; environment constructor (define-syntax (make-env stx) diff --git a/typed-racket-more/typed/framework.rkt b/typed-racket-more/typed/framework.rkt index 96280930e..6e73dbf33 100644 --- a/typed-racket-more/typed/framework.rkt +++ b/typed-racket-more/typed/framework.rkt @@ -62,6 +62,7 @@ (define -Continuation-Mark-Set (-opq #'continuation-mark-set?)) (define -Struct Univ) ; FIXME (define -Text:Range (-opq #'text:range?)) + ; Frequently reused instances (define -Color%-Instance (make-Instance -Color%)) @@ -88,6 +89,9 @@ (define -Window<%>-Instance (make-Instance -Window<%>)) (define -DC<%>-Instance (make-Instance -DC<%>))) +(require "racket/generate-predef-con.rkt" + typed-racket/base-env/base-types-extra) + (type-environment [application:current-app-name (-Param -String)] ;; 3 Autosave diff --git a/typed-racket-more/typed/racket/draw.rkt b/typed-racket-more/typed/racket/draw.rkt index 4d06fe4fe..fd2ffbf3a 100644 --- a/typed-racket-more/typed/racket/draw.rkt +++ b/typed-racket-more/typed/racket/draw.rkt @@ -82,6 +82,9 @@ (define -Font-Hinting (parse-type #'Font-Hinting)) (define -LoadFileKind (parse-type #'LoadFileKind))) +(require "generate-predef-con.rkt" + typed-racket/base-env/base-types-extra) + (type-environment [bitmap% (parse-type #'Bitmap%)] [bitmap-dc% (parse-type #'Bitmap-DC%)] diff --git a/typed-racket-more/typed/racket/generate-predef-con.rkt b/typed-racket-more/typed/racket/generate-predef-con.rkt new file mode 100644 index 000000000..c2bd73827 --- /dev/null +++ b/typed-racket-more/typed/racket/generate-predef-con.rkt @@ -0,0 +1,69 @@ +#lang racket/base +(require (for-syntax + typed-racket/private/type-contract + racket/base racket/match + racket/syntax + typed-racket/private/parse-type + typed-racket/base-env/base-types-extra + typed-racket/env/env-req) + typed-racket/base-env/base-types-extra) +;; generate a good symbol name for this contract +;; Syntax -> Symbol +(define-for-syntax (->name stx) + (syntax-case stx (Instance) + [(Instance i) (format-symbol "~a-instance/c" #'i)] + [i (identifier? #'i) (syntax-e #'i)] + [_ 'gui_base/c])) + + +(provide generate-contract-submods) + +(define-syntax (generate-contract-submods stx) + (do-requires) + (do-contract-requires) + (define cache (make-hash)) + (define sc-cache (make-hash)) + (define sets-stx null) + (define defs-stx null) + (define (generate-contracts ty-name kind [side 'typed]) + (define typ (parse-type ty-name)) + (define name (->name ty-name)) + (match-define (list defs ctc) + (type->contract + typ + #:typed-side (from-typed? side) + #:kind kind + #:cache (make-hash) + #:sc-cache (make-hash) + (lambda _ (error 'fail)))) + (define n (datum->syntax #'here (syntax-e (generate-temporary name)))) + (set! defs-stx (append defs-stx defs + (list + #`(provide #,n) + #`(define #,n #,ctc)))) + (set! sets-stx (cons #`(hash-set! predef-contracts + (cons (parse-type #'#,ty-name) '#,side) + #'#,n) + sets-stx))) + (syntax-case stx () + [(_ [ty kind (modes ...)] ...) + (for ([ty (syntax->list #'(ty ...))] + [kind (syntax->list #'(kind ...))] + [modes (syntax->list #'((modes ...) ...))]) + (for ([mode (syntax->list modes)]) + (generate-contracts ty (syntax-e kind) (syntax-e mode))))]) + + #`(begin + (module* #%contract-defs #f + (#%plain-module-begin + #,@(get-contract-requires) + #,@defs-stx)) + (begin-for-syntax + (module* #%contract-defs-names #f + (require #,(syntax-local-introduce + #'(submod typed-racket/static-contracts/instantiate + predefined-contracts)) + typed-racket/private/parse-type + typed-racket/base-env/base-types-extra + #,(syntax-local-introduce #'(for-template (submod ".." #%contract-defs)))) + #,@(map syntax-local-introduce sets-stx))))) diff --git a/typed-racket-more/typed/racket/gui.rkt b/typed-racket-more/typed/racket/gui.rkt index 5316ec614..7132998cf 100644 --- a/typed-racket-more/typed/racket/gui.rkt +++ b/typed-racket-more/typed/racket/gui.rkt @@ -5,8 +5,8 @@ (require "gui/base.rkt" typed/racket) -(provide (all-from-out "gui/base.rkt") - (all-from-out typed/racket)) +(#%provide (all-from "gui/base.rkt") + (all-from typed/racket)) ;; language definition (module reader syntax/module-reader diff --git a/typed-racket-more/typed/racket/gui/base.rkt b/typed-racket-more/typed/racket/gui/base.rkt index a270a3f81..ff664c77f 100644 --- a/typed-racket-more/typed/racket/gui/base.rkt +++ b/typed-racket-more/typed/racket/gui/base.rkt @@ -24,6 +24,9 @@ (define -Color% (parse-type #'Color%)) (define -Color%-Obj (make-Instance -Color%))) +(require "../generate-predef-con.rkt" + typed-racket/base-env/base-types-extra) + (type-environment [button% (parse-type #'Button%)] [canvas% (parse-type #'Canvas%)] diff --git a/typed-racket-more/typed/racket/snip.rkt b/typed-racket-more/typed/racket/snip.rkt index aee0e6261..27a17f61a 100644 --- a/typed-racket-more/typed/racket/snip.rkt +++ b/typed-racket-more/typed/racket/snip.rkt @@ -17,6 +17,9 @@ Style-Delta% Style-List%) +(require "generate-predef-con.rkt" + typed-racket/base-env/base-types-extra) + (type-environment [snip% (parse-type #'Snip%)] [snip-admin% (parse-type #'Snip-Admin%)] diff --git a/typed-racket-more/typed/untyped-utils.rkt b/typed-racket-more/typed/untyped-utils.rkt index baab35b5f..2662d70bc 100644 --- a/typed-racket-more/typed/untyped-utils.rkt +++ b/typed-racket-more/typed/untyped-utils.rkt @@ -1,19 +1,26 @@ #lang racket/base + +(module stxtime racket/base + (require (submod typed-racket/utils/tc-utils typed-context)) + (define (syntax-local-typed-context?) (unbox typed-context?)) + (provide syntax-local-typed-context?)) + (require (for-syntax racket/base syntax/parse syntax/stx racket/syntax typed-racket/utils/tc-utils typed-racket/typecheck/renamer) - typed-racket/utils/tc-utils) + (submod "." stxtime) + (for-syntax (submod "." stxtime))) (provide syntax-local-typed-context? + (for-syntax syntax-local-typed-context?) define-typed/untyped-identifier require/untyped-contract) -(define (syntax-local-typed-context?) - (unbox typed-context?)) + (define-syntax (define-typed/untyped-identifier stx) (syntax-parse stx diff --git a/typed-racket-test/unit-tests/contract-tests.rkt b/typed-racket-test/unit-tests/contract-tests.rkt index 5aebf61c2..70c3184b6 100644 --- a/typed-racket-test/unit-tests/contract-tests.rkt +++ b/typed-racket-test/unit-tests/contract-tests.rkt @@ -4,7 +4,7 @@ (for-syntax racket/base syntax/parse) (for-template racket/base) - (private type-contract) + (except-in (private type-contract) type->contract) (rep type-rep values-rep) (types abbrev numeric-tower prop-ops) (static-contracts combinators optimize)