Make struct: form have the correct bindings in struct info.

Also fixes reexport of struct-type to typed modules.

Reexport issue.
Closes PR13160.

Constructor issue.
Closes PR13161.

Struct copy issues.
Closes PR 10765.
Closes PR 12513.
Closes PR 13149.
This commit is contained in:
Eric Dobson 2012-10-20 13:38:10 -07:00
parent 4a4c8418dc
commit 9586dca0a3
11 changed files with 163 additions and 51 deletions

View File

@ -60,6 +60,7 @@ This file defines two sorts of primitives. All of them are provided into any mod
racket/lazy-require racket/lazy-require
syntax/parse syntax/parse
syntax/stx syntax/stx
racket/list
racket/syntax racket/syntax
unstable/sequence unstable/sequence
unstable/syntax unstable/syntax
@ -604,12 +605,14 @@ This file defines two sorts of primitives. All of them are provided into any mod
(syntax-parse stx (syntax-parse stx
[(_ vars:maybe-type-vars nm:struct-name (fs:fld-spec ...) [(_ vars:maybe-type-vars nm:struct-name (fs:fld-spec ...)
opts:struct-options) opts:struct-options)
(let ([mutable? (if (attribute opts.mutable?) #'(#:mutable) #'())]) (let ([mutable? (if (attribute opts.mutable?) #'(#:mutable) #'())]
[cname (second (build-struct-names #'nm.name empty #t #t))])
(with-syntax ([d-s (ignore-some-property (with-syntax ([d-s (ignore-some-property
(syntax/loc stx (define-struct nm (fs.fld ...) . opts)) (syntax/loc stx (define-struct nm (fs.fld ...) . opts))
#t)] #t)]
[dtsi (quasisyntax/loc stx [dtsi (quasisyntax/loc stx
(dtsi* (vars.vars ...) nm (fs ...) (dtsi* (vars.vars ...) nm (fs ...)
#:maker #,cname
#,@mutable?))]) #,@mutable?))])
(if (eq? (syntax-local-context) 'top-level) (if (eq? (syntax-local-context) 'top-level)
;; Use `eval` at top-level to avoid an unbound id error ;; Use `eval` at top-level to avoid an unbound id error
@ -632,17 +635,14 @@ This file defines two sorts of primitives. All of them are provided into any mod
(syntax-parse stx (syntax-parse stx
[(_ vars:maybe-type-vars nm:struct-name/new (fs:fld-spec ...) [(_ vars:maybe-type-vars nm:struct-name/new (fs:fld-spec ...)
opts:struct-options) opts:struct-options)
(let ([mutable? (if (attribute opts.mutable?) #'(#:mutable) #'())] (let ([mutable? (if (attribute opts.mutable?) #'(#:mutable) #'())])
[cname (datum->syntax #f (format-symbol "make-~a" (syntax-e #'nm.name)))])
(with-syntax ([d-s (ignore-property (quasisyntax/loc stx (with-syntax ([d-s (ignore-property (quasisyntax/loc stx
(struct #,@(attribute nm.new-spec) (fs.fld ...) (struct #,@(attribute nm.new-spec) (fs.fld ...)
#:extra-constructor-name #,cname
. opts)) . opts))
#t)] #t)]
[dtsi (quasisyntax/loc stx [dtsi (quasisyntax/loc stx
(dtsi* (vars.vars ...) (dtsi* (vars.vars ...)
nm.old-spec (fs ...) nm.old-spec (fs ...)
#:maker #,cname
#,@mutable?))]) #,@mutable?))])
;; see comment above ;; see comment above
(if (eq? (syntax-local-context) 'top-level) (if (eq? (syntax-local-context) 'top-level)

View File

@ -14,6 +14,7 @@
(env type-env-structs global-env mvar-env) (env type-env-structs global-env mvar-env)
(utils tc-utils) (utils tc-utils)
(only-in (rep type-rep) Type/c) (only-in (rep type-rep) Type/c)
(typecheck renamer)
(except-in (types utils abbrev kw-types) -> ->* one-of/c)) (except-in (types utils abbrev kw-types) -> ->* one-of/c))
(provide lexical-env with-lexical-env with-lexical-env/extend (provide lexical-env with-lexical-env with-lexical-env/extend
@ -41,6 +42,12 @@
(define (lookup-type/lexical i [env (lexical-env)] #:fail [fail #f]) (define (lookup-type/lexical i [env (lexical-env)] #:fail [fail #f])
(lookup env i (λ (i) (lookup-type i (λ () (lookup env i (λ (i) (lookup-type i (λ ()
(cond (cond
[(syntax-property i 'constructor-for)
=> (λ (prop)
(define orig (un-rename prop))
(define t (lookup-type/lexical orig env))
(register-type i t)
t)]
[(syntax-procedure-alias-property i) [(syntax-procedure-alias-property i)
=> (λ (prop) => (λ (prop)
(define orig (car (flatten prop))) (define orig (car (flatten prop)))

View File

@ -5,10 +5,12 @@
(define-struct binding (name) #:transparent) (define-struct binding (name) #:transparent)
(define-struct (def-binding binding) (ty) #:transparent) (define-struct (def-binding binding) (ty) #:transparent)
(define-struct (def-stx-binding binding) () #:transparent) (define-struct (def-stx-binding binding) () #:transparent)
(define-struct (def-struct-stx-binding def-stx-binding) (static-info) #:transparent) (define-struct (def-struct-stx-binding def-stx-binding) (static-info constructor-type) #:transparent)
(provide/cond-contract (provide/cond-contract
(struct binding ([name identifier?])) (struct binding ([name identifier?]))
(struct (def-binding binding) ([name identifier?] [ty any/c])) (struct (def-binding binding) ([name identifier?] [ty any/c]))
(struct (def-stx-binding binding) ([name identifier?])) (struct (def-stx-binding binding) ([name identifier?]))
(struct (def-struct-stx-binding binding) ([name identifier?] [static-info (or/c #f struct-info?)]))) (struct (def-struct-stx-binding binding) ([name identifier?]
[static-info (or/c #f struct-info?)]
[constructor-type any/c])))

View File

@ -30,6 +30,12 @@
;; defs: defines in this module ;; defs: defines in this module
;; provs: provides in this module ;; provs: provides in this module
;; pos-blame-id: a #%variable-reference for the module ;; pos-blame-id: a #%variable-reference for the module
;; The first returned value is a syntax object of definitions that defines the
;; contracted versions of the provided identifiers, and the corresponding
;; provides.
;;
;; The second value is a list of two element lists, which are type name aliases.
(define (generate-prov defs provs pos-blame-id) (define (generate-prov defs provs pos-blame-id)
;; maps ids defined in this module to an identifier which is the possibly-contracted version of the key ;; maps ids defined in this module to an identifier which is the possibly-contracted version of the key
(define mapping (make-free-id-table)) (define mapping (make-free-id-table))
@ -59,17 +65,17 @@
[(dict-ref defs internal-id #f) [(dict-ref defs internal-id #f)
=> =>
(match-lambda (match-lambda
[(def-binding _ (app (λ (ty) (type->contract ty (λ () #f))) cnt)) [(def-binding _ ty)
(mk-value-triple internal-id new-id cnt)] (mk-value-triple internal-id new-id ty)]
[(def-struct-stx-binding _ (? struct-info? si)) [(def-struct-stx-binding _ (? struct-info? si) constr-type)
(mk-struct-syntax-triple internal-id new-id si)] (mk-struct-syntax-triple internal-id new-id si constr-type)]
[(def-stx-binding _) [(def-stx-binding _)
(mk-syntax-triple internal-id new-id)])] (mk-syntax-triple internal-id new-id)])]
;; otherwise, not defined in this module, not our problem ;; otherwise, not defined in this module, not our problem
[else (values #'(begin) internal-id null)])) [else (values #'(begin) internal-id null)]))
;; mk-struct-syntax-triple : identifier? identifier? struct-info? -> triple/c ;; mk-struct-syntax-triple : identifier? identifier? struct-info? Type/c -> triple/c
(define (mk-struct-syntax-triple internal-id new-id si) (define (mk-struct-syntax-triple internal-id new-id si constr-type)
(define type-is-constructor? #t) ;Conservative estimate (provide/contract does the same) (define type-is-constructor? #t) ;Conservative estimate (provide/contract does the same)
(match-define (list type-desc constr pred (list accs ...) muts super) (extract-struct-info si)) (match-define (list type-desc constr pred (list accs ...) muts super) (extract-struct-info si))
(define-values (defns new-ids aliases) (define-values (defns new-ids aliases)
@ -77,24 +83,37 @@
(lambda (e) (if (identifier? e) (lambda (e) (if (identifier? e)
(mk e) (mk e)
(values #'(begin) e null))) (values #'(begin) e null)))
(list* type-desc constr pred super accs))) (list* type-desc pred super accs)))
(define/with-syntax (type-desc* constr* pred* super* accs* ...) (define-values (constr-defn constr-new-id constr-aliases)
(for/list ([i (in-list new-ids)]) (if (identifier? i) #`(syntax #,i) i))) (cond
[(not (identifier? constr))
(values #'(begin) #f null)]
[(free-identifier=? constr internal-id)
(mk-value-triple constr (generate-temporary constr) constr-type)]
[else
(mk constr)]))
(define/with-syntax (constr* type-desc* pred* super* accs* ...)
(for/list ([i (in-list (cons constr-new-id new-ids))])
(and (identifier? i) #`(quote-syntax #,i))))
(with-syntax* ([id internal-id] (with-syntax* ([id internal-id]
[export-id new-id] [export-id new-id]
[untyped-id (freshen-id #'id)]) [protected-id (freshen-id #'id)])
(values (values
#`(begin #`(begin
#,constr-defn
#,@defns #,@defns
(define-syntax untyped-id (define-syntax protected-id
(let ((info (list type-desc* constr* pred* (list accs* ...) (let ((info (list type-desc* (syntax export-id) pred* (list accs* ...)
(list #,@(map (lambda (x) #'#f) accs)) super*))) (list #,@(map (lambda (x) #'#f) accs)) super*)))
#,(if type-is-constructor? #,(if type-is-constructor?
#'(make-struct-info-self-ctor constr* info) #'(make-struct-info-self-ctor constr* info)
#'info))) #'info)))
(def-export export-id id untyped-id)) (def-export export-id protected-id protected-id))
new-id new-id
(cons (list #'export-id internal-id) (apply append aliases))))) (cons (list #'export-id internal-id)
(apply append constr-aliases aliases)))))
;; mk-syntax-triple : identifier? identifier? -> triple/c ;; mk-syntax-triple : identifier? identifier? -> triple/c
@ -112,16 +131,18 @@
(list (list #'export-id #'id))))) (list (list #'export-id #'id)))))
;; mk-value-triple : identifier? identifier? (or/c syntax? #f) -> triple/c ;; mk-value-triple : identifier? identifier? (or/c syntax? #f) -> triple/c
(define (mk-value-triple internal-id new-id cnt) (define (mk-value-triple internal-id new-id ty)
(define contract (type->contract ty (λ () #f)))
(with-syntax* ([id internal-id] (with-syntax* ([id internal-id]
[untyped-id (freshen-id #'id)] [untyped-id (freshen-id #'id)]
[export-id new-id]) [export-id new-id])
(define/with-syntax definitions (define/with-syntax definitions
(if cnt (if contract
(with-syntax* ([module-source pos-blame-id] (with-syntax* ([module-source pos-blame-id]
[the-contract (generate-temporary 'generated-contract)]) [the-contract (generate-temporary 'generated-contract)])
#`(begin #`(begin
(define the-contract #,cnt) (define the-contract #,contract)
(define-syntax untyped-id (define-syntax untyped-id
(make-provide/contract-transformer (make-provide/contract-transformer
(quote-syntax the-contract) (quote-syntax the-contract)

View File

@ -1,6 +1,6 @@
#lang racket/base #lang racket/base
(provide renamer get-alternate) (provide renamer get-alternate un-rename)
;; target : identifier ;; target : identifier
;; alternate : identifier ;; alternate : identifier
@ -21,3 +21,16 @@
(if alt (if alt
(make-typed-renaming (syntax-property id 'not-free-identifier=? #t) alt) (make-typed-renaming (syntax-property id 'not-free-identifier=? #t) alt)
(make-rename-transformer (syntax-property id 'not-free-identifier=? #t)))) (make-rename-transformer (syntax-property id 'not-free-identifier=? #t))))
;; Undo renaming for type lookup.
;; Used because of macros that mark the identifier used as the binding such as
;; kw-application or struct constructors
;;
;; The syntax-transforming check is for unit tests
(define (un-rename id)
(if (syntax-transforming?)
(let-values (((binding new-id) (syntax-local-value/immediate id (lambda () (values #f #f)))))
(if (typed-renaming? binding)
new-id
id))
id))

View File

@ -95,10 +95,10 @@
(if (null? l) (if (null? l)
(values (reverse getters) (reverse setters)) (values (reverse getters) (reverse setters))
(loop (cddr l) (cons (car l) getters) (cons (cadr l) setters))))) (loop (cddr l) (cons (car l) getters) (cons (cadr l) setters)))))
(match (build-struct-names nm flds #f #f nm) (match (build-struct-names nm flds #f #f nm #:constructor-name maker*)
[(list sty maker pred getters/setters ...) [(list sty maker pred getters/setters ...)
(let-values ([(getters setters) (split getters/setters)]) (let-values ([(getters setters) (split getters/setters)])
(struct-names nm sty (or maker* maker) pred getters setters))])) (struct-names nm sty maker pred getters setters))]))
;; gets the fields of the parent type, if they exist ;; gets the fields of the parent type, if they exist
;; Option[Struct-Ty] -> Listof[Type] ;; Option[Struct-Ty] -> Listof[Type]
@ -166,13 +166,12 @@
(define bindings (define bindings
(list* (list*
;; the list of names w/ types ;; the list of names w/ types
(cons (struct-names-struct-type names) (make-StructType sty)) (make-def-binding (struct-names-struct-type names) (make-StructType sty))
(cons (struct-names-constructor names) (poly-wrapper (->* all-fields poly-base))) (make-def-binding (struct-names-predicate names)
(cons (struct-names-predicate names) (make-pred-ty (if (not covariant?)
(make-pred-ty (if (not covariant?) (make-StructTop sty)
(make-StructTop sty) (subst-all (make-simple-substitution
(subst-all (make-simple-substitution tvars (map (const Univ) tvars)) poly-base))))
tvars (map (const Univ) tvars)) poly-base))))
(append (append
(for/list ([g (in-list (struct-names-getters names))] (for/list ([g (in-list (struct-names-getters names))]
[t (in-list self-fields)] [t (in-list self-fields)]
@ -183,28 +182,31 @@
(->* (list poly-base) t) (->* (list poly-base) t)
(->acc (list poly-base) t (list path))))]) (->acc (list poly-base) t (list path))))])
(add-struct-fn! g path #f) (add-struct-fn! g path #f)
(cons g func))) (make-def-binding g func)))
(if mutable (if mutable
(for/list ([s (in-list (struct-names-setters names))] (for/list ([s (in-list (struct-names-setters names))]
[t (in-list self-fields)] [t (in-list self-fields)]
[i (in-naturals parent-count)]) [i (in-naturals parent-count)])
(add-struct-fn! s (make-StructPE poly-base i) #t) (add-struct-fn! s (make-StructPE poly-base i) #t)
(cons s (poly-wrapper (->* (list poly-base t) -Void)))) (make-def-binding s (poly-wrapper (->* (list poly-base t) -Void))))
null)))) null))))
(add-struct-constructor! (struct-names-constructor names)) (add-struct-constructor! (struct-names-constructor names))
(define def-bindings (define constructor-binding
(for/list ([b (in-list bindings)]) (make-def-binding (struct-names-constructor names) (poly-wrapper (->* all-fields poly-base))))
(define id (car b))
(define t (cdr b)) (for ([b (cons constructor-binding bindings)])
(register-type id t) (register-type (binding-name b) (def-binding-ty b)))
(make-def-binding id t)))
(if si (append
(cons (if (free-identifier=? (struct-names-type-name names)
(make-def-struct-stx-binding (struct-names-type-name names) si) (struct-names-constructor names))
def-bindings) null
def-bindings)) (list constructor-binding))
(cons
(make-def-struct-stx-binding (struct-names-type-name names) si (def-binding-ty constructor-binding))
bindings)))
(define (register-parsed-struct-sty! ps) (define (register-parsed-struct-sty! ps)
(match ps (match ps

View File

@ -49,7 +49,7 @@
#:attr name #'nm.nm #:attr name #'nm.nm
#:attr mutable (attribute fields.mutable) #:attr mutable (attribute fields.mutable)
#:attr type-only (attribute fields.type-only) #:attr type-only (attribute fields.type-only)
#:attr maker (attribute fields.maker))) #:attr maker (or (attribute fields.maker) #'nm.nm)))
(define (parse-define-struct-internal form) (define (parse-define-struct-internal form)
(parameterize ([current-orig-stx form]) (parameterize ([current-orig-stx form])
@ -331,7 +331,17 @@
(define def-tbl (define def-tbl
(for/fold ([h (make-immutable-free-id-table)]) (for/fold ([h (make-immutable-free-id-table)])
([def (in-list defs)]) ([def (in-list defs)])
(dict-set h (binding-name def) def))) ;; TODO figure out why without these checks some tests break
(define (plain-stx-binding? def)
(and (def-stx-binding? def) (not (def-struct-stx-binding? def))))
(define (merge-def-bindings other-def)
(cond
[(not other-def) def]
[(plain-stx-binding? def) other-def]
[(plain-stx-binding? other-def) def]
[else
(int-err "Two conflicting definitions: ~a ~a" def other-def)]))
(dict-update h (binding-name def) merge-def-bindings #f)))
;; typecheck the expressions and the rhss of defintions ;; typecheck the expressions and the rhss of defintions
;(displayln "Starting pass2") ;(displayln "Starting pass2")
(for-each tc-toplevel/pass2 forms) (for-each tc-toplevel/pass2 forms)

View File

@ -0,0 +1,17 @@
#lang racket/load
(module A typed/racket
(struct: Point ([x : Integer] [y : Integer]))
(provide (all-defined-out)))
(module B typed/racket
(require 'A)
(: lift (Point -> Point))
(define (lift p)
(struct-copy Point p [x (add1 (Point-x p))]))
(lift (Point 3 4)))
(require 'B)

View File

@ -0,0 +1,14 @@
#lang racket/load
(module a typed/racket/base
(provide (struct-out the-struct))
(struct: the-struct ((a : Number))))
(module b typed/racket/base
(require 'a)
(provide (struct-out the-struct)))
(require 'b)
(the-struct 5)

View File

@ -0,0 +1,10 @@
#lang typed/racket/base
(provide (struct-out x)
make-x)
(struct: x () #:transparent)
(: make-x : -> x)
(define (make-x)
(x))

View File

@ -0,0 +1,16 @@
#lang racket/load
(module t1 typed/racket
(provide node)
(struct: node ()))
(module t2 typed/racket
(require 't1)
(: v node)
(define v (node)))
(module u racket
(require 't1)
(node))
(require 't2)
(require 'u)