From f4c1d7ec032f3a1aabdc5e4cd0b0021b55f8d8e4 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Wed, 6 Aug 2014 08:46:51 +0100 Subject: [PATCH] racket/class: add missing check for # When a superclass method is called before the superclass is initialized, then all field accesses need to be guarded. Robby found this one. --- .../racket-test/tests/racket/object.rktl | 39 ++++++++++++------- .../collects/racket/private/class-undef.rkt | 13 +++++-- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/pkgs/racket-pkgs/racket-test/tests/racket/object.rktl b/pkgs/racket-pkgs/racket-test/tests/racket/object.rktl index ea856f62eb..070cc475bc 100644 --- a/pkgs/racket-pkgs/racket-test/tests/racket/object.rktl +++ b/pkgs/racket-pkgs/racket-test/tests/racket/object.rktl @@ -1927,6 +1927,11 @@ ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; check error reporting for variable use before assignment +(define (make-undefined-exn? name) + (lambda (exn) + (and (exn:fail:contract:variable? exn) + (eq? name (exn:fail:contract:variable-id exn))))) + (let () (define c% (class object% @@ -1962,21 +1967,25 @@ (field [s 1]) (super-new))) - (err/rt-test (new d%) (lambda (exn) - (and (exn:fail:contract:variable? exn) - (eq? 'z (exn:fail:contract:variable-id exn))))) - (err/rt-test (new d!%) (lambda (exn) - (and (exn:fail:contract:variable? exn) - (eq? 'z (exn:fail:contract:variable-id exn))))) - (err/rt-test (new e%) (lambda (exn) - (and (exn:fail:contract:variable? exn) - (eq? 'z (exn:fail:contract:variable-id exn))))) - (err/rt-test (new d2%) (lambda (exn) - (and (exn:fail:contract:variable? exn) - (eq? 'f (exn:fail:contract:variable-id exn))))) - (err/rt-test (new e2%) (lambda (exn) - (and (exn:fail:contract:variable? exn) - (eq? 'f (exn:fail:contract:variable-id exn)))))) + (err/rt-test (new d%) (make-undefined-exn? 'z)) + (err/rt-test (new d!%) (make-undefined-exn? 'z)) + (err/rt-test (new e%) (make-undefined-exn? 'z)) + (err/rt-test (new d2%) (make-undefined-exn? 'f)) + (err/rt-test (new e2%) (make-undefined-exn? 'f))) + +(let () + (define c% + (class object% + (field [s #f]) + (define/public (set-s) + (set! s #f)) + (super-new))) + (define d% + (class c% + (inherit set-s) + (set-s) + (super-new))) + (err/rt-test (new d%) (make-undefined-exn? 's))) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; check optimization to omit use-before-definition chaperone: diff --git a/racket/collects/racket/private/class-undef.rkt b/racket/collects/racket/private/class-undef.rkt index ac9060dfd1..f636a33ed8 100644 --- a/racket/collects/racket/private/class-undef.rkt +++ b/racket/collects/racket/private/class-undef.rkt @@ -124,10 +124,15 @@ (free-identifier=? #'decl #'declare-this-escapes)) ;; Any method call or explicit use of `this` means a field ;; might be accessed outside of the `class` declaration, - ;; so any initialization afterward is too late: - (begin - (when ready (set! init-too-late? #t)) - (loop #'(begin . body)))] + ;; so `super-new` had better be done, and any initialization + ;; afterward is too late: + (or (and ready + (not super-new?) + (report #'body) + #t) + (begin + (when ready (set! init-too-late? #t)) + (loop #'(begin . body))))] [(begin '(decl) . body) (and (identifier? #'decl)