diff --git a/collects/tests/typed-scheme/optimizer/generic/structs.rkt b/collects/tests/typed-scheme/optimizer/generic/structs.rkt new file mode 100644 index 00000000..4fb39c9d --- /dev/null +++ b/collects/tests/typed-scheme/optimizer/generic/structs.rkt @@ -0,0 +1,6 @@ +(module structs typed/scheme #:optimize + (require racket/unsafe/ops) + (define-struct: pt ((x : Integer) (y : Integer)) #:mutable) + (define a (pt 3 4)) + (pt-x a) + (set-pt-y! a 5)) diff --git a/collects/typed-scheme/private/optimize.rkt b/collects/typed-scheme/private/optimize.rkt index fecbaaba..1feeb4b7 100644 --- a/collects/typed-scheme/private/optimize.rkt +++ b/collects/typed-scheme/private/optimize.rkt @@ -249,6 +249,18 @@ (lambda (x) #t) (lambda (x y) #t))))) + ;; we can always optimize struct accessors and mutators + ;; if they typecheck, they're safe + (pattern (#%plain-app op:id s:opt-expr v:opt-expr ...) + #:when (or (struct-accessor? #'op) (struct-mutator? #'op)) + #:with opt + (let ([idx (struct-fn-idx #'op)]) + (if (struct-accessor? #'op) + (begin (log-optimization "struct ref" #'op) + #`(unsafe-struct-ref s.opt #,idx)) + (begin (log-optimization "struct set" #'op) + #`(unsafe-struct-set! s.opt #,idx v.opt ...))))) + ;; boring cases, just recur down (pattern (#%plain-lambda formals e:opt-expr ...) #:with opt #'(#%plain-lambda formals e.opt ...)) diff --git a/collects/typed-scheme/types/type-table.rkt b/collects/typed-scheme/types/type-table.rkt index 154ac941..8e742f21 100644 --- a/collects/typed-scheme/types/type-table.rkt +++ b/collects/typed-scheme/types/type-table.rkt @@ -22,10 +22,15 @@ (let () (define ((mk mut?) id) (cond [(dict-ref struct-fn-table id #f) - => (match-lambda [(list pe #f) pe] [_ #f])] + => (match-lambda [(list pe m) (and (eq? m mut?) pe)] [_ #f])] [else #f])) (values (mk #f) (mk #t)))) +(define (struct-fn-idx id) + (match (dict-ref struct-fn-table id #f) + [(list (StructPE: _ idx) _) idx] + [_ (int-err (format "no struct fn table entry for ~a" (syntax->datum id)))])) + (define (make-struct-table-code) (parameterize ([current-print-convert-hook converter] [show-sharing #f]) @@ -43,4 +48,5 @@ [add-struct-fn! (identifier? StructPE? boolean? . -> . any/c)] [struct-accessor? (identifier? . -> . (or/c #f StructPE?))] [struct-mutator? (identifier? . -> . (or/c #f StructPE?))] + [struct-fn-idx (identifier? . -> . exact-integer?)] [make-struct-table-code (-> syntax?)]) \ No newline at end of file