Add support for override

This commit is contained in:
Asumu Takikawa 2013-05-18 14:17:06 -04:00
parent 060aaa8b26
commit 931556264e
3 changed files with 56 additions and 18 deletions

View File

@ -238,7 +238,8 @@
(init #,@(dict-ref name-dict #'init '())) (init #,@(dict-ref name-dict #'init '()))
(init-field #,@(dict-ref name-dict #'init-field '())) (init-field #,@(dict-ref name-dict #'init-field '()))
(field #,@(dict-ref name-dict #'field '())) (field #,@(dict-ref name-dict #'field '()))
(public #,@(dict-ref name-dict #'public '())))) (public #,@(dict-ref name-dict #'public '()))
(override #,@(dict-ref name-dict #'override '()))))
(class #,annotated-super (class #,annotated-super
#,@(map clause-stx clauses) #,@(map clause-stx clauses)
#,@(map non-clause-stx annotated-methods) #,@(map non-clause-stx annotated-methods)
@ -264,10 +265,11 @@
;; if it's a method definition for a declared method, then ;; if it's a method definition for a declared method, then
;; mark it as something to type-check ;; mark it as something to type-check
;; FIXME: this needs to handle external/internal names too ;; FIXME: this needs to handle external/internal names too
;; FIXME: this needs to track overrides and other things ;; FIXME: this needs to track privates, augments, etc.
[(define-values (id) . rst) [(define-values (id) . rst)
#:when (memf (λ (n) (free-identifier=? #'id n)) #:when (memf (λ (n) (free-identifier=? #'id n))
(dict-ref name-dict #'public)) (append (dict-ref name-dict #'public '())
(dict-ref name-dict #'override '())))
(values (cons (non-clause (syntax-property stx (values (cons (non-clause (syntax-property stx
'tr:class:method 'tr:class:method
(syntax-e #'id))) (syntax-e #'id)))
@ -288,10 +290,13 @@
;; set!-transformers to the appropriate accessors, which lets ;; set!-transformers to the appropriate accessors, which lets
;; us figure out the accessor identifiers. ;; us figure out the accessor identifiers.
(define (make-locals-table name-dict) (define (make-locals-table name-dict)
(syntax-property (define method-names
#`(let-values ([(#,@(dict-ref name-dict #'public '())) (append (dict-ref name-dict #'public '())
(values #,@(map (λ (stx) #`(λ () (#,stx))) (dict-ref name-dict #'override '())))
(dict-ref name-dict #'public '())))]) (syntax-property
(void)) #`(let-values ([(#,@method-names)
'tr:class:local-table #t))) (values #,@(map (λ (stx) #`(λ () (#,stx)))
method-names))])
(void))
'tr:class:local-table #t)))

View File

@ -48,7 +48,7 @@
(syntax-parse form (syntax-parse form
#:literals (let-values #%plain-lambda quote-syntax begin #:literals (let-values #%plain-lambda quote-syntax begin
#%plain-app values class:-internal letrec-syntaxes+values #%plain-app values class:-internal letrec-syntaxes+values
c:init c:init-field c:field c:public) c:init c:init-field c:field c:public c:override)
;; Inspect the expansion of the class macro for the pieces that ;; Inspect the expansion of the class macro for the pieces that
;; we need to type-check like superclass, methods, top-level ;; we need to type-check like superclass, methods, top-level
;; expressions and so on ;; expressions and so on
@ -63,7 +63,8 @@
(c:init internal-init-names ...) (c:init internal-init-names ...)
(c:init-field internal-init-field-names ...) (c:init-field internal-init-field-names ...)
(c:field internal-field-names ...) (c:field internal-field-names ...)
(c:public internal-public-names ...))) (c:public internal-public-names ...)
(c:override internal-override-names ...)))
(#%plain-app values)))) (#%plain-app values))))
(let-values (((superclass) superclass-expr) (let-values (((superclass) superclass-expr)
((interfaces) interface-expr)) ((interfaces) interface-expr))
@ -103,8 +104,12 @@
(list->set (list->set
(append (syntax->datum #'(internal-field-names ...)) (append (syntax->datum #'(internal-field-names ...))
(syntax->datum #'(internal-init-field-names ...))))) (syntax->datum #'(internal-init-field-names ...)))))
(define this%-method-names (define this%-public-names
(list->set (syntax->datum #'(internal-public-names ...)))) (list->set (syntax->datum #'(internal-public-names ...))))
(define this%-override-names
(list->set (syntax->datum #'(internal-override-names ...))))
(define this%-method-names
(set-union this%-public-names this%-override-names))
;; Use the internal class: information to check whether clauses ;; Use the internal class: information to check whether clauses
;; exist or are absent appropriately ;; exist or are absent appropriately
(when expected? (when expected?
@ -114,20 +119,22 @@
(check-exists (set-union this%-init-names super-init-names) (check-exists (set-union this%-init-names super-init-names)
exp-init-names exp-init-names
"initialization argument") "initialization argument")
(check-exists (set-union this%-method-names super-method-names) (check-exists (set-union this%-public-names super-method-names)
exp-method-names exp-method-names
"public method") "public method")
(check-exists (set-union this%-field-names super-field-names) (check-exists (set-union this%-field-names super-field-names)
exp-field-names exp-field-names
"public field")) "public field"))
(check-exists super-method-names this%-override-names
"override method")
(check-absent super-field-names this%-field-names "public field") (check-absent super-field-names this%-field-names "public field")
(check-absent super-method-names this%-method-names "public method") (check-absent super-method-names this%-public-names "public method")
;; FIXME: the control flow for the failure of these checks is ;; FIXME: the control flow for the failure of these checks is
;; still up in the air ;; still up in the air
#| #|
(check-no-extra (set-union this%-field-names super-field-names) (check-no-extra (set-union this%-field-names super-field-names)
exp-field-names) exp-field-names)
(check-no-extra (set-union this%-method-names super-method-names) (check-no-extra (set-union this%-public-names super-method-names)
exp-method-names) exp-method-names)
|# |#
;; trawl the body for the local name table ;; trawl the body for the local name table
@ -151,7 +158,7 @@
;; trawl the body and find methods and type-check them ;; trawl the body and find methods and type-check them
(define meths (trawl-for-property #'body 'tr:class:method)) (define meths (trawl-for-property #'body 'tr:class:method))
(with-lexical-env/extend (map (λ (m) (dict-ref local-table m)) (with-lexical-env/extend (map (λ (m) (dict-ref local-table m))
(syntax->datum #'(internal-public-names ...))) (set->list this%-method-names))
;; FIXME: the types we put here are fine in the expected ;; FIXME: the types we put here are fine in the expected
;; case, but not if the class doesn't have an annotation. ;; case, but not if the class doesn't have an annotation.
;; Then we need to hunt down annotations in a first pass. ;; Then we need to hunt down annotations in a first pass.
@ -161,7 +168,7 @@
(map (λ (m) (->* (list (make-Univ)) (map (λ (m) (->* (list (make-Univ))
(fixup-method-type (car (dict-ref methods m)) (fixup-method-type (car (dict-ref methods m))
self-type))) self-type)))
(syntax->datum #'(internal-public-names ...))) (set->list this%-method-names))
(for ([meth meths]) (for ([meth meths])
(define method-name (syntax-property meth 'tr:class:method)) (define method-name (syntax-property meth 'tr:class:method))
(define method-type (define method-type

View File

@ -259,5 +259,31 @@
(: c% (Class (init [x Integer]))) (: c% (Class (init [x Integer])))
(define c% (class: object% (super-new) (init x))) (define c% (class: object% (super-new) (init x)))
(: d% (Class)) (: d% (Class))
(define d% (class: c% (super-new [x "bad"])))))) (define d% (class: c% (super-new [x "bad"]))))
;; test override
(check-ok
(: c% (Class [m (Integer -> Integer)]))
(define c% (class: object% (super-new)
(define/public (m y) (add1 y))))
(: d% (Class [m (Integer -> Integer)]))
(define d% (class: c% (super-new)
(define/override (m y) (* 2 y)))))
;; test local call to overriden method
(check-ok
(: c% (Class [m (Integer -> Integer)]))
(define c% (class: object% (super-new)
(define/public (m y) (add1 y))))
(: d% (Class [n (Integer -> Integer)]
[m (Integer -> Integer)]))
(define d% (class: c% (super-new)
(define/public (n x) (m x))
(define/override (m y) (* 2 y)))))
;; fails, superclass missing public for override
(check-err
(: d% (Class [m (Integer -> Integer)]))
(define d% (class: object% (super-new)
(define/override (m y) (* 2 y)))))))