diff --git a/racket/src/cs/rumble/error.ss b/racket/src/cs/rumble/error.ss index 3f1eab1dd4..0734f1c46b 100644 --- a/racket/src/cs/rumble/error.ss +++ b/racket/src/cs/rumble/error.ss @@ -548,9 +548,9 @@ (string->symbol (format "body of ~a" n)))) (let* ([c (#%$continuation-return-code k)] [n (#%$code-name c)]) - (if (special-procedure-name-string? n) + (if (path-or-empty-procedure-name-string? n) #f - n)))] + (procedure-name-string->visible-name-string n))))] [desc (let* ([ci (#%$code-info (#%$continuation-return-code k))] [src (and diff --git a/racket/src/cs/rumble/object-name.ss b/racket/src/cs/rumble/object-name.ss index 31cd25691a..ba3004c951 100644 --- a/racket/src/cs/rumble/object-name.ss +++ b/racket/src/cs/rumble/object-name.ss @@ -40,19 +40,8 @@ [else (let ([name (#%$code-name (#%$closure-code v))]) (and name - (cond - [(special-procedure-name-string? name) - ;; "[" is "no name", and any other - ;; "["-prefixed name is derived from the path - (let ([len (string-length name)]) - (and (fx> len 1) - (string->symbol (substring name 1 len))))] - [(and (fx> (string-length name) 0) - (char=? #\] (string-ref name 0))) - ;; Strip escape character - (string->symbol (substring name 1 (string-length name)))] - [else - (string->symbol name)])))])] + (let ([n (procedure-name-string->visible-name-string name)]) + (and n (string->symbol n)))))])] [(impersonator? v) (object-name (impersonator-val v))] [(procedure? v) @@ -76,9 +65,45 @@ (getprop (record-type-uid rtd) 'prefab-key+count #f))) (object-name (record-rtd v))))) +;; Since a procedure name is the one way we have to attach static +;; information to `lambda` forms, it can encode more than just a name: +;; * Starting with "[" means a path-derived name, where that +;; distinction is used instack trace. +;; * Starting with "]" means that some other starting character +;; ws escaped. +;; * After "[" or "]", "!" means a method, and "^" means not-a-method. +(define (procedure-name-string->visible-name-string n) + (cond + [(not (string? n)) n] + [else + (let ([len (string-length n)]) + (cond + [(fx= 0 len) n] + [else + (let ([strip-prefix + (lambda () + (cond + [(fx= 1 len) ""] + [(char=? #\; (string-ref n 0)) + (substring n 2 len)] + [(char=? #\^ (string-ref n 0)) + (substring n 2 len)] + [else + (substring n 1 len)]))]) + (cond + [(char=? #\[ (string-ref n 0)) + (let ([n (strip-prefix)]) + ;; Empty means no name + (if (eqv? "" n) + #f + n))] + [(char=? #\] (string-ref n 0)) + (strip-prefix)] + [else n]))]))])) + ;; name starting with a square bracket is meant to ;; encode a path or "no name" -(define (special-procedure-name-string? n) +(define (path-or-empty-procedure-name-string? n) (and (string? n) (fx> (string-length n) 0) (char=? #\[ (string-ref n 0)))) diff --git a/racket/src/cs/rumble/procedure.ss b/racket/src/cs/rumble/procedure.ss index b992a419ca..f444ffbf27 100644 --- a/racket/src/cs/rumble/procedure.ss +++ b/racket/src/cs/rumble/procedure.ss @@ -376,7 +376,7 @@ (let ([name (wrapper-procedure-data f)]) (and (#%vector? name) (method-wrapper-vector? name))) - #f)] + (procedure-is-method-by-name? f))] [(record? f) (or (method-arity-error? f) (let ([v (struct-property-ref prop:procedure (record-rtd f) #f)]) @@ -391,8 +391,47 @@ [else (procedure-is-method? v)])))] [else #f])) -(define-syntax-rule (|#%method-arity| e) - (procedure->method e)) +(define (procedure-is-method-by-name? proc) + (let ([n (#%$code-name (#%$closure-code proc))]) + (and n + (fx>= (string-length n) 2) + (or (char=? #\[ (string-ref n 0)) + (char=? #\] (string-ref n 0))) + (char=? #\! (string-ref n 1))))) + +(define-syntax (|#%method-arity| stx) + (syntax-case stx (|#%name|) + [(_ (|#%name| name e)) + ;; Encode method-arity property in the procedure name; see + ;; "object-name.ss" for more information about encoding + (let ([n (#%symbol->string (#%syntax->datum #'name))]) + (let ([new-name + (#%string->symbol + (cond + [(= 0 (string-length n)) + ;; "]" indicates encoded, and "!" indicates method + "]!"] + [(or (char=? #\[ (string-ref n 0)) + (char=? #\] (string-ref n 0))) + ;; Path-based, no name, or escaped: + (cond + [(= 1 (string-length n)) + ;; No name or empty, so change to method + (string-append n "!")] + [(char=? #\! (string-ref n 1)) + ;; Already marked as a method + n] + [(char=? #\^ (string-ref n 1)) + ;; Currently marked as "not a method" + (string-append (#%substring n 0 1) "!" (#%substring n 2 (string-length n)))] + [else + ;; Currently a path-based name or escaped name + (string-append (#%substring n 0 1) "!" (#%substring n 1 (string-length n)))])] + [else + ;; Add an escape so we can mark as a method: + (string-append "]!" n)]))]) + #`(|#%name| #,(#%datum->syntax #'name new-name) e)))] + [(_ e) #'(procedure->method e)])) ;; ---------------------------------------- @@ -462,13 +501,15 @@ (vector (or name (#%vector-ref v 0)) (#%vector-ref v 1) 'method)] - [name (vector name + [name (vector (or name (#%vector-ref v 0)) (#%vector-ref v 1))] [else v])))] [(#%procedure? proc) (make-arity-wrapper-procedure proc mask - (vector name proc))] + (if (procedure-is-method-by-name? proc) + (vector name proc 'method) + (vector name proc)))] [(reduced-arity-procedure? proc) (do-procedure-reduce-arity-mask (reduced-arity-procedure-proc proc) mask diff --git a/racket/src/schemify/infer-name.rkt b/racket/src/schemify/infer-name.rkt index 0cf4898676..7ba4d53646 100644 --- a/racket/src/schemify/infer-name.rkt +++ b/racket/src/schemify/infer-name.rkt @@ -30,11 +30,17 @@ (define (add-property str) (wrap-property-set (reannotate orig-s new-s) 'inferred-name - ;; Hack: starting with "[" means - ;; "derived from path". This distinction - ;; is used when printing function names - ;; in a stack trace. - (string->symbol (string-append-immutable "[" str)))) + ;; Starting with "[" means "derived from + ;; path". This distinction is used when + ;; printing function names in a stack trace. + ;; Furthermore, "!" or "^" after "[" indicates + ;; methodness or not, so add an explicit "^" + ;; if necessary. + (let ([prefix (if (or (char=? (string-ref str 0) #\!) + (char=? (string-ref str 0) #\^)) + "[^" + "[")]) + (string->symbol (string-append-immutable prefix str))))) (cond [(and (or (path? src) (string? src)) line col) (add-property @@ -54,7 +60,7 @@ ;; suppress any other inferred name: (wrap-property-set (reannotate orig-s new-s) 'inferred-name - ;; Hack: "[" means "no name" + ;; "[" means "no name" '|[|)] [else new-s])]))