Handle init/init-field order correctly in TR

Also handles the case where init and init-field clauses
are interleaved, in which case they need to be interleaved
in the type.

Closes PR 14408

original commit: a21a4a151ace08457a38d2af0664aecf44c30f0a
This commit is contained in:
Asumu Takikawa 2014-03-19 01:41:59 -04:00
parent d9dca81616
commit bbb47f45fe
3 changed files with 43 additions and 6 deletions

View File

@ -341,12 +341,14 @@
(define-values (annotated-methods other-top-level private-fields)
(process-class-contents others name-dict))
(define annotated-super (tr:class:super-property #'super #t))
(define ordered-inits (get-all-init-names clauses))
(define optional-inits (get-optional-inits clauses))
(ignore
(tr:class
#`(let-values ()
#,(internal (make-class-name-table (attribute forall.type-variables)
private-fields
ordered-inits
optional-inits
name-dict))
(untyped-class #,annotated-super
@ -450,6 +452,14 @@
#:when optional?)
(stx-car id-pair)))))
;; get-all-init-names : Listof<Clause> -> Listof<Id>
;; Get a list of all the (internal) init names in order
(define (get-all-init-names clauses)
(flatten
(for/list ([clause clauses]
#:when (init-clause? clause))
(stx-map stx-car (clause-ids clause)))))
;; check-unsupported-features : Dict<Identifier, Names> -> Void
;; Check if features that are not supported were used and
;; raise an error if they are present
@ -462,14 +472,19 @@
"unsupported class clause: ~a"
(syntax-e form)))))
;; make-class-name-table : Listof<Id> Listof<Id> Listof<Id> Dict<Id, Id> -> Stx
;; make-class-name-table : Listof<Id> Listof<Id> Listof<Id>
;; Listof<Id> Dict<Id, Id> -> Stx
;; construct syntax used by the class type-checker as a reliable source
;; for the member names that are in a given class, plus any type
;; variables that are bound
(define (make-class-name-table foralls private-fields
optional-inits name-dict)
(define (make-class-name-table foralls
private-fields
ordered-inits
optional-inits
name-dict)
#`(class-internal
(#:forall #,@foralls)
(#:all-inits #,@ordered-inits)
(init #,@(dict-ref name-dict #'init '()))
(init-field #,@(dict-ref name-dict #'init-field '()))
(init-rest #,@(dict-ref name-dict #'init-rest '()))

View File

@ -74,6 +74,7 @@
(pattern (begin (quote-syntax
(class-internal
(#:forall type-parameter:id ...)
(#:all-inits all-init-names:id ...)
(c:init init-names:name-pair ...)
(c:init-field init-field-names:name-pair ...)
(c:init-rest (~optional init-rest-name:id))
@ -89,6 +90,7 @@
(c:pubment pubment-names:name-pair ...)))
(#%plain-app values))
#:with type-parameters #'(type-parameter ...)
#:with all-init-internals #'(all-init-names ...)
#:with init-internals #'(init-names.internal ...)
#:with init-externals #'(init-names.external ...)
#:with init-field-internals #'(init-field-names.internal ...)
@ -160,6 +162,7 @@
#:literals (let-values letrec-syntaxes+values #%plain-app)
#:attributes (superclass-expr
type-parameters
all-init-internals
init-internals init-externals
init-field-internals init-field-externals
init-rest-name
@ -252,9 +255,9 @@
'optional-inits (syntax->datum #'cls.optional-inits)
'only-init-internals (syntax->datum #'cls.init-internals)
'only-init-names (syntax->datum #'cls.init-externals)
'init-internals
(set-union (syntax->datum #'cls.init-internals)
(syntax->datum #'cls.init-field-internals))
;; the order of these names reflect the order in the class,
;; so use this list when retaining the order is important
'init-internals (syntax->datum #'cls.all-init-internals)
'init-rest-name (and (attribute cls.init-rest-name)
(syntax-e (attribute cls.init-rest-name)))
'public-internals (syntax->datum #'cls.public-internals)

View File

@ -1251,6 +1251,25 @@
(init-rest [rst : (List Symbol)])))
(make-object c% "wrong"))
#:msg #rx"expected: Symbol.*given: String"]
;; PR 14408, test init-field order
[tc-e (let ()
(define c%
(class object%
(super-new)
(init-field [x : String] [y : Symbol])))
(make-object c% "str" 'sym)
(void))
-Void]
;; a variant of the last, but testing that init and init-field
;; interleave correctly in the class type
[tc-e (let ()
(define c%
(class object%
(super-new)
(init [a : 'a]) (init-field [x : 'x] [y : 'y]) (init [b 'b])))
(make-object c% 'a 'x 'y 'b)
(void))
-Void]
;; fail, too many positional arguments to superclass
[tc-err (class object% (super-make-object "foo"))
#:msg #rx"too many positional init arguments"]