From 49387b2bc67f90650e5c2a982d8fb31e7e6d90b7 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 2 Mar 2021 16:03:52 -0500 Subject: [PATCH] add Type to kwargs internal argument (#39593) Fixes #39419 --- base/essentials.jl | 20 ++++++++++++++++++++ base/iterators.jl | 22 +++++----------------- src/julia-syntax.scm | 21 +++++++++++---------- test/iterators.jl | 2 +- 4 files changed, 37 insertions(+), 28 deletions(-) diff --git a/base/essentials.jl b/base/essentials.jl index 62a63afa55576..636db9df67a10 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -23,6 +23,26 @@ An `AbstractDict{K, V}` should be an iterator of `Pair{K, V}`. """ abstract type AbstractDict{K,V} end +""" + Iterators.Pairs(values, keys) <: AbstractDict{eltype(keys), eltype(values)} + +Transforms an indexable container into an Dictionary-view of the same data. +Modifying the key-space of the underlying data may invalidate this object. +""" +struct Pairs{K, V, I, A} <: AbstractDict{K, V} + data::A + itr::I +end +Pairs{K, V}(data::A, itr::I) where {K, V, I, A} = Pairs{K, V, I, A}(data, itr) +Pairs{K}(data::A, itr::I) where {K, I, A} = Pairs{K, eltype(A), I, A}(data, itr) +Pairs(data::A, itr::I) where {I, A} = Pairs{eltype(I), eltype(A), I, A}(data, itr) +pairs(::Type{NamedTuple}) = Pairs{Symbol, V, NTuple{N, Symbol}, NamedTuple{names, T}} where {V, N, names, T<:NTuple{N, Any}} + +## optional pretty printer: +#const NamedTuplePair{N, V, names, T<:NTuple{N, Any}} = Pairs{Symbol, V, NTuple{N, Symbol}, NamedTuple{names, T}} +#export NamedTuplePair + + # The real @inline macro is not available until after array.jl, so this # internal macro splices the meta Expr directly into the function body. macro _inline_meta() diff --git a/base/iterators.jl b/base/iterators.jl index af5e108845afb..eebffed16dcfb 100644 --- a/base/iterators.jl +++ b/base/iterators.jl @@ -9,7 +9,7 @@ module Iterators import ..@__MODULE__, ..parentmodule const Base = parentmodule(@__MODULE__) using .Base: - @inline, Pair, AbstractDict, IndexLinear, IndexCartesian, IndexStyle, AbstractVector, Vector, + @inline, Pair, Pairs, AbstractDict, IndexLinear, IndexCartesian, IndexStyle, AbstractVector, Vector, tail, SizeUnknown, HasLength, HasShape, IsInfinite, EltypeUnknown, HasEltype, OneTo, @propagate_inbounds, @isdefined, @boundscheck, @inbounds, Generator, AbstractRange, LinearIndices, (:), |, +, -, !==, !, <=, <, missing, any, _counttuple @@ -177,18 +177,6 @@ end (i, n[1]), (i-1, ri, n[2]) end -""" - Iterators.Pairs(values, keys) <: AbstractDict{eltype(keys), eltype(values)} - -Transforms an indexable container into an Dictionary-view of the same data. -Modifying the key-space of the underlying data may invalidate this object. -""" -struct Pairs{K, V, I, A} <: AbstractDict{K, V} - data::A - itr::I - Pairs(data::A, itr::I) where {A, I} = new{eltype(I), eltype(A), I, A}(data, itr) -end - """ pairs(IndexLinear(), A) pairs(IndexCartesian(), A) @@ -240,11 +228,11 @@ pairs(::IndexCartesian, A::AbstractArray) = Pairs(A, CartesianIndices(axes(A))) # preserve indexing capabilities for known indexable types # faster than zip(keys(a), values(a)) for arrays +pairs(tuple::Tuple) = Pairs{Int}(tuple, keys(tuple)) +pairs(nt::NamedTuple) = Pairs{Symbol}(nt, keys(nt)) +pairs(v::Core.SimpleVector) = Pairs(v, LinearIndices(v)) pairs(A::AbstractArray) = pairs(IndexCartesian(), A) pairs(A::AbstractVector) = pairs(IndexLinear(), A) -pairs(tuple::Tuple) = Pairs(tuple, keys(tuple)) -pairs(nt::NamedTuple) = Pairs(nt, keys(nt)) -pairs(v::Core.SimpleVector) = Pairs(v, LinearIndices(v)) # pairs(v::Pairs) = v # listed for reference, but already defined from being an AbstractDict length(v::Pairs) = length(v.itr) @@ -266,7 +254,7 @@ reverse(v::Pairs) = Pairs(v.data, reverse(v.itr)) haskey(v::Pairs, key) = (key in v.itr) keys(v::Pairs) = v.itr -values(v::Pairs) = v.data +values(v::Pairs) = v.data # TODO: this should be a view of data subset by itr getindex(v::Pairs, key) = v.data[key] setindex!(v::Pairs, value, key) = (v.data[key] = value; v) get(v::Pairs, key, default) = get(v.data, key, default) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index c6a65ebe15c60..e798fe5d1e217 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -470,15 +470,16 @@ (filter (lambda (s) (not (any (lambda (p) (eq? (car p) (car s))) positional-sparams))) - sparams))) - (let ((kw (gensy)) - (rkw (if (null? restkw) (make-ssavalue) (symbol (string (car restkw) "...")))) - (mangled (let ((und (and name (undot-name name)))) - (symbol (string (if (and name (= (string.char (string name) 0) #\#)) - "" - "#") - (or und '_) "#" - (string (current-julia-module-counter))))))) + sparams)) + (kw (gensy)) + (rkw (if (null? restkw) (make-ssavalue) (symbol (string (car restkw) "...")))) + (restkw (map (lambda (v) `(|::| ,v (call (top pairs) (core NamedTuple)))) restkw)) + (mangled (let ((und (and name (undot-name name)))) + (symbol (string (if (and name (= (string.char (string name) 0) #\#)) + "" + "#") + (or und '_) "#" + (string (current-julia-module-counter))))))) ;; this is a hack: nest these statements inside a call so they get closure ;; converted together, allowing all needed types to be defined before any methods. `(call (core ifelse) (false) (false) (block @@ -579,7 +580,7 @@ (list `(... ,(arg-name (car vararg))))))))))) ;; return primary function ,(if (not (symbol? name)) - '(null) name)))))) + '(null) name))))) ;; prologue includes line number node and eventual meta nodes (define (extract-method-prologue body) diff --git a/test/iterators.jl b/test/iterators.jl index f4432c9d831cd..b45a51fd87042 100644 --- a/test/iterators.jl +++ b/test/iterators.jl @@ -618,7 +618,7 @@ end @test isempty(d) || haskey(d, first(keys(d))) @test collect(v for (k, v) in d) == collect(A) if A isa NamedTuple - K = isempty(d) ? Union{} : Symbol + K = Symbol V = isempty(d) ? Union{} : Float64 @test isempty(d) || haskey(d, :a) @test !haskey(d, :abc)