diff --git a/src/ast.scm b/src/ast.scm index a20f8f87f955c..15e55fc616041 100644 --- a/src/ast.scm +++ b/src/ast.scm @@ -493,6 +493,7 @@ (define (vinfo:never-undef v) (< 0 (logand (caddr v) 4))) (define (vinfo:read v) (< 0 (logand (caddr v) 8))) (define (vinfo:sa v) (< 0 (logand (caddr v) 16))) +(define (vinfo:nospecialize v) (< 0 (logand (caddr v) 128))) (define (set-bit x b val) (if val (logior x b) (logand x (lognot b)))) ;; record whether var is captured (define (vinfo:set-capt! v c) (set-car! (cddr v) (set-bit (caddr v) 1 c))) @@ -507,6 +508,7 @@ ;; occurs undef: mask 32 ;; whether var is called (occurs in function call head position) (define (vinfo:set-called! v a) (set-car! (cddr v) (set-bit (caddr v) 64 a))) +(define (vinfo:set-nospecialize! v c) (set-car! (cddr v) (set-bit (caddr v) 128 c))) (define var-info-for assq) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 8f0bcd55ac194..cf2c964cf2374 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -3492,10 +3492,15 @@ (define (analyze-vars e env captvars sp tab) (if (or (atom? e) (quoted? e)) (begin - (if (symbol? e) - (let ((vi (get tab e #f))) - (if vi - (vinfo:set-read! vi #t)))) + (cond + ((symbol? e) + (let ((vi (get tab e #f))) + (if vi + (vinfo:set-read! vi #t)))) + ((nospecialize-meta? e) + (let ((vi (get tab (caddr e) #f))) + (if vi + (vinfo:set-nospecialize! vi #t))))) e) (case (car e) ((local-def) ;; a local that we know has an assignment that dominates all usages @@ -3594,21 +3599,6 @@ f(x) = yt(x) (call (core _typebody!) (false) ,s (call (core svec) ,@types)) (return (null))))))))) -(define (type-for-closure name fields super) - (let ((s (make-ssavalue))) - `((thunk ,(linearize `(lambda () - (() () 0 ()) - (block (global ,name) - (= ,s (call (core _structtype) (thismodule) (inert ,name) (call (core svec)) - (call (core svec) ,@(map quotify fields)) - (call (core svec)) - (false) ,(length fields))) - (call (core _setsuper!) ,s ,super) - (const (globalref (thismodule) ,name) ,s) - (call (core _typebody!) (false) ,s - (call (core svec) ,@(map (lambda (v) '(core Box)) fields))) - (return (null))))))))) - ;; better versions of above, but they get handled wrong in many places ;; need to fix that in order to handle #265 fully (and use the definitions) @@ -4022,6 +4012,10 @@ f(x) = yt(x) (let ((cv (assq v (cadr (lam:vinfo lam))))) (and cv (vinfo:asgn cv) (vinfo:capt cv))))) +(define (is-var-nospecialize? v lam) + (let ((vi (assq v (car (lam:vinfo lam))))) + (and vi (vinfo:nospecialize vi)))) + (define (toplevel-preserving? e) (and (pair? e) (memq (car e) '(if elseif block trycatch tryfinally trycatchelse)))) @@ -4313,16 +4307,14 @@ f(x) = yt(x) (closure-param-syms (map (lambda (s) (make-ssavalue)) closure-param-names)) (typedef ;; expression to define the type (let* ((fieldtypes (map (lambda (v) - (if (is-var-boxed? v lam) - '(core Box) - (make-ssavalue))) + (cond ((is-var-boxed? v lam) '(core Box)) + ((is-var-nospecialize? v lam) (vinfo:type (assq v (car (lam:vinfo lam))))) + (else (make-ssavalue)))) capt-vars)) (para (append closure-param-syms (filter ssavalue? fieldtypes))) (fieldnames (append closure-param-names (filter (lambda (v) (not (is-var-boxed? v lam))) capt-vars)))) - (if (null? para) - (type-for-closure type-name capt-vars '(core Function)) - (type-for-closure-parameterized type-name para fieldnames capt-vars fieldtypes '(core Function))))) + (type-for-closure-parameterized type-name para fieldnames capt-vars fieldtypes '(core Function)))) (mk-method ;; expression to make the method (if short '() (let* ((iskw ;; TODO jb/functions need more robust version of this @@ -4352,7 +4344,7 @@ f(x) = yt(x) (P (append closure-param-names (filter identity (map (lambda (v ve) - (if (is-var-boxed? v lam) + (if (or (is-var-boxed? v lam) (is-var-nospecialize? v lam)) #f `(call (core _typeof_captured_variable) ,ve))) capt-vars var-exprs))))) diff --git a/test/syntax.jl b/test/syntax.jl index 4116bdef23a52..0c56b6b74b167 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -4330,3 +4330,12 @@ let ex = @Meta.lower function return_my_method(); 1; end code[end] = Core.ReturnNode(Core.SSAValue(idx)) @test isa(Core.eval(@__MODULE__, ex), Method) end + +# Capturing a @nospecialize argument should result in an Any field in the closure +module NoSpecClosure + K(@nospecialize(x)) = y -> x +end +let f = NoSpecClosure.K(1) + @test f(2) == 1 + @test typeof(f).parameters == Core.svec() +end