diff --git a/base/namedtuple.jl b/base/namedtuple.jl index 050d460f24724..01fbeeec694e3 100644 --- a/base/namedtuple.jl +++ b/base/namedtuple.jl @@ -316,8 +316,8 @@ end keys(nt::NamedTuple{names}) where {names} = names values(nt::NamedTuple) = Tuple(nt) haskey(nt::NamedTuple, key::Union{Integer, Symbol}) = isdefined(nt, key) -get(nt::NamedTuple, key::Union{Integer, Symbol}, default) = haskey(nt, key) ? getfield(nt, key) : default -get(f::Callable, nt::NamedTuple, key::Union{Integer, Symbol}) = haskey(nt, key) ? getfield(nt, key) : f() +get(nt::NamedTuple, key::Union{Integer, Symbol}, default) = isdefined(nt, key) ? getfield(nt, key) : default +get(f::Callable, nt::NamedTuple, key::Union{Integer, Symbol}) = isdefined(nt, key) ? getfield(nt, key) : f() tail(t::NamedTuple{names}) where names = NamedTuple{tail(names)}(t) front(t::NamedTuple{names}) where names = NamedTuple{front(names)}(t) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 0e3888d76da33..10c204e1c50a6 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -441,6 +441,11 @@ (block ,(scopenest (cdr names) (cdr vals) expr))))) +(define (make-assignments names vals expr) + `(block + ,@(map make-assignment names vals) + ,expr)) + (define (keywords-method-def-expr name sparams argl body rett) (let* ((kargl (cdar argl)) ;; keyword expressions (= k v) (annotations (map (lambda (a) `(meta ,(cadr a) ,(arg-name (cadr (caddr a))))) @@ -487,6 +492,15 @@ (lambda (x) (eq? x v)) vals)) keynames)) + ;; if keyword args don't depend on each other and the default + ;; values don't have embedded assignments (ick) then we can use + ;; ssavalues instead of slots in the sorter method. + (ssa-keyvars? (and (not ordered-defaults) + (not (contains assignment? vals)))) + (keyvars (if ssa-keyvars? + (map (lambda (x) (make-ssavalue)) keynames) + keynames)) + (tempslot (gensy)) ;; list of function's initial line number and meta nodes (empty if none) (prologue (extract-method-prologue body)) ;; body statements @@ -554,11 +568,16 @@ `(meta ,(cadr m) ,@(filter (lambda (v) (not (memq v keynames))) (cddr m)))) (filter nospecialize-meta? prologue)) - ,(scopenest - keynames + ;; If not using slots for the keyword argument values, still declare them + ;; for reflection purposes. + ,@(if ssa-keyvars? + (map (lambda (v) `(local ,v)) (reverse keynames)) + '()) + ,((if ssa-keyvars? make-assignments scopenest) + keyvars (map (lambda (v dflt) (let* ((k (decl-var v)) - (rval0 `(call (top getindex) ,kw (inert ,k))) + (rval0 `(call (core getfield) ,kw (inert ,k))) ;; note: if the "declared" type of a KW arg includes something ;; from keyword-sparams then don't assert it here, since those ;; static parameters don't have values yet. instead, the type @@ -580,9 +599,10 @@ ,temp))) ,temp)) rval0))) - `(if (call (top haskey) ,kw (quote ,k)) - ,rval - ,dflt))) + `(block (if (call (core isdefined) ,kw (quote ,k)) + (= ,tempslot ,rval) + (= ,tempslot ,dflt)) + ,tempslot))) vars vals) `(block (= ,rkw (call (top pairs) @@ -596,7 +616,7 @@ (call (top kwerr) ,kw ,@(map arg-name pargl) ,@splatted-vararg))) '()) (return (call ,mangled ;; finally, call the core function - ,@keynames + ,@keyvars ,@(if (null? restkw) '() (list rkw)) ,@(map arg-name pargl) ,@splatted-vararg))))))