Skip to content

Commit 84ea027

Browse files
committed
fix a bug in typechecking structs' extra constructor names
When the extra constructor name was the same as the structure name, it would mistakenly introduce two conflict definitions. The new changes make sure the extra constructor name is not set under the same condition.
1 parent 66ba341 commit 84ea027

File tree

6 files changed

+50
-47
lines changed

6 files changed

+50
-47
lines changed

typed-racket-lib/typed-racket/base-env/prims-contract.rkt

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -408,30 +408,7 @@
408408

409409

410410
(module self-ctor racket/base
411-
(require racket/struct-info)
412-
413-
;Copied from racket/private/define-struct
414-
;FIXME when multiple bindings are supported
415-
(define (self-ctor-transformer orig stx)
416-
(define (transfer-srcloc orig stx)
417-
(datum->syntax orig (syntax-e orig) stx orig))
418-
(syntax-case stx ()
419-
[(self arg ...) (datum->syntax stx
420-
(cons (syntax-property (transfer-srcloc orig #'self)
421-
'constructor-for
422-
(syntax-local-introduce #'self))
423-
(syntax-e (syntax (arg ...))))
424-
stx
425-
stx)]
426-
[_ (transfer-srcloc orig stx)]))
427-
(define make-struct-info-self-ctor
428-
(let ()
429-
(struct struct-info-self-ctor (id info)
430-
#:property prop:procedure
431-
(lambda (ins stx)
432-
(self-ctor-transformer (struct-info-self-ctor-id ins) stx))
433-
#:property prop:struct-info (λ (x) (extract-struct-info (struct-info-self-ctor-info x))))
434-
struct-info-self-ctor))
411+
(require "../utils/utils.rkt")
435412
(provide make-struct-info-self-ctor))
436413

437414
(require (submod "." self-ctor))

typed-racket-lib/typed-racket/typecheck/def-binding.rkt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
(define-struct binding (name) #:transparent)
88
(define-struct (def-binding binding) (ty) #:transparent)
99
(define-struct (def-stx-binding binding) () #:transparent)
10-
(define-struct (def-struct-stx-binding def-stx-binding) (static-info constructor-type extra-ctor-name) #:transparent)
10+
(define-struct (def-struct-stx-binding def-stx-binding) (static-info constructor-type extra-constr-name) #:transparent)
1111

1212
(provide/cond-contract
1313
(struct binding ([name identifier?]))
@@ -16,4 +16,4 @@
1616
(struct (def-struct-stx-binding binding) ([name identifier?]
1717
[static-info (or/c #f struct-info?)]
1818
[constructor-type any/c]
19-
[extra-ctor-name (or/c #f identifier?)])))
19+
[extra-constr-name (or/c #f identifier?)])))

typed-racket-lib/typed-racket/typecheck/internal-forms.rkt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,16 @@
101101
#:attr mutable (attribute options.mutable)
102102
#:attr prefab (attribute options.prefab)
103103
#:attr type-only (attribute options.type-only)
104-
#:attr maker (or (attribute options.maker) #'nm.nm)
105-
#:attr extra-maker (attribute options.extra-maker)
104+
#:with maker^ (or (attribute options.maker) #'nm.nm)
105+
#:attr maker #'maker^
106+
#:attr extra-maker (let ([em (attribute options.extra-maker)]
107+
[m #'maker^])
108+
;; extra-maker is only assigned to an id if
109+
;; options.extra-maker is set and is *not* the
110+
;; same as maker. Otherwise, it is false. This
111+
;; assumption simplifies handling the extra
112+
;; constructor in tc-structs
113+
(and em (not (free-identifier=? em m)) em))
106114
#:attr properties (attribute options.prop)))
107115

108116
(define-syntax-class dviu-import/export

typed-racket-lib/typed-racket/typecheck/provide-handling.rkt

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
(types struct-table)
1111
(utils tc-utils)
1212
(env env-utils)
13-
(base-env type-name-error)
1413
(for-syntax racket/base)
1514
(for-template racket/base))
1615

@@ -86,16 +85,16 @@
8685
(match-lambda
8786
[(def-binding _ ty)
8887
(mk-value-quad internal-id new-id ty)]
89-
[(def-struct-stx-binding _ (? struct-info? si) constr-type extra-ctor-name)
90-
(mk-struct-syntax-quad internal-id new-id si constr-type extra-ctor-name)]
88+
[(def-struct-stx-binding _ (? struct-info? si) constr-type extra-constr-name)
89+
(mk-struct-syntax-quad internal-id new-id si constr-type extra-constr-name)]
9190
[(def-stx-binding _)
9291
(mk-syntax-quad internal-id new-id)])]
9392
;; otherwise, not defined in this module, not our problem
9493
[else (mk-ignored-quad internal-id)]))
9594

96-
;; mk-struct-syntax-quad : identifier? identifier? struct-info? Type? -> quad/c
95+
;; mk-struct-syntax-quad : identifier? identifier? struct-info? Type? (or/c identifier? #f) -> quad/c
9796
;; This handles `(provide s)` where `s` was defined with `(struct s ...)`.
98-
(define (mk-struct-syntax-quad internal-id new-id si constr-type extra-ctor-name)
97+
(define (mk-struct-syntax-quad internal-id new-id si constr-type extra-constr-name)
9998
(match-define (list type-desc constr pred (list accs ...) muts super) (extract-struct-info si))
10099
(define-values (defns export-defns new-ids aliases)
101100
(for/lists (defns export-defns new-ids aliases)
@@ -104,7 +103,7 @@
104103
(mk e)
105104
(mk-ignored-quad e))))
106105

107-
(define type-is-constructor? (or (free-identifier=? new-id constr) extra-ctor-name))
106+
(define type-is-constructor? (and (or (free-identifier=? new-id constr) extra-constr-name) #t))
108107
;; Here, we recursively handle all of the identifiers referenced
109108
;; in this static struct info.
110109
(define-values (constr-defn constr-export-defn constr-new-id constr-aliases)
@@ -122,7 +121,8 @@
122121

123122
(with-syntax* ([id internal-id]
124123
[export-id new-id]
125-
[protected-id (freshen-id #'id)])
124+
[protected-id (freshen-id #'id)]
125+
[type-is-constr? type-is-constructor?])
126126
(values
127127
#`(begin
128128
#,constr-defn
@@ -143,10 +143,7 @@
143143
(define-syntax protected-id
144144
(let ((info (list type-desc* (syntax export-id) pred* (list accs* ...)
145145
(list #,@(map (lambda (x) #'#f) accs)) super*)))
146-
#,(if type-is-constructor?
147-
#'(make-struct-info-self-ctor constr* info)
148-
#'(lambda (stx)
149-
(type-name-error stx)))))
146+
(make-struct-info-self-ctor constr* info type-is-constr?)))
150147
(define-syntax export-id
151148
(make-rename-transformer #'protected-id)))
152149
#'export-id

typed-racket-lib/typed-racket/utils/utils.rkt

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ at least theoretically.
109109
(define-requirer base-env base-env-out)
110110
(define-requirer static-contracts static-contracts-out)
111111

112+
(require "../base-env/type-name-error.rkt")
113+
112114
;; turn contracts on and off - off by default for performance.
113115
(provide (for-syntax enable-contracts?)
114116
provide/cond-contract
@@ -230,14 +232,17 @@ at least theoretically.
230232
[_ (transfer-srcloc orig stx)]))
231233

232234

233-
(define make-struct-info-self-ctor
234-
(let ()
235-
(struct struct-info-self-ctor (id info)
236-
#:property prop:procedure
237-
(lambda (ins stx)
238-
(self-ctor-transformer (struct-info-self-ctor-id ins) stx))
239-
#:property prop:struct-info (λ (x) (extract-struct-info (struct-info-self-ctor-info x))))
240-
struct-info-self-ctor))
235+
(define (make-struct-info-self-ctor id info [flag #t])
236+
(let ()
237+
(struct struct-info-self-ctor (id info type-is-constr?)
238+
#:property prop:procedure
239+
(lambda (ins stx)
240+
(if (struct-info-self-ctor-type-is-constr? ins)
241+
(self-ctor-transformer (struct-info-self-ctor-id ins) stx)
242+
(type-name-error stx)))
243+
#:property prop:struct-info (λ (x) (extract-struct-info (struct-info-self-ctor-info x))))
244+
(struct-info-self-ctor id info flag)))
245+
241246

242247
;; Listof[A] Listof[B] B -> Listof[B]
243248
;; pads out t to be as long as s
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#lang typed/racket/base
2+
(module a-mod typed/racket/base
3+
(provide (except-out (all-defined-out) make-avocado))
4+
(struct apple ())
5+
(struct orange () #:constructor-name make-orange)
6+
(struct kiwi () #:constructor-name kiwi)
7+
(struct pear () #:extra-constructor-name pear)
8+
(struct avocado () #:type-name Avocado #:constructor-name make-avocado))
9+
10+
(require 'a-mod)
11+
(apple)
12+
(make-orange)
13+
(kiwi)
14+
(: avocado-id (-> Avocado Avocado))
15+
(define (avocado-id arg) arg)
16+
(struct hass-avocado avocado ())

0 commit comments

Comments
 (0)