text:
@doc raw"""
    exp(M::AbstractManifold, p, X)
    exp(M::AbstractManifold, p, X, t::Real = 1)

Compute the exponential map of tangent vector `X`, optionally scaled by `t`,  at point `p`
from the manifold [`AbstractManifold`](@ref) `M`, i.e.

```math
\exp_p X = γ_{p,X}(1),
```
where ``γ_{p,X}`` is the unique geodesic starting in ``γ(0)=p`` such that ``\dot γ(0) = X``.

See also [`shortest_geodesic`](@ref), [`retract`](@ref).
"""
function exp(M::AbstractManifold, p, X)
    q = allocate_result(M, exp, p, X)
    exp!(M, q, p, X)
    return q
end
exp(M::AbstractManifold, p, X, t::Real) = exp(M, p, t * X)

"""
    exp!(M::AbstractManifold, q, p, X)
    exp!(M::AbstractManifold, q, p, X, t::Real = 1)

Compute the exponential map of tangent vector `X`, optionally scaled by `t`,  at point `p`
from the manifold [`AbstractManifold`](@ref) `M`.
The result is saved to `q`.

See also [`exp`](@ref).
"""
exp!(M::AbstractManifold, q, p, X)
exp!(M::AbstractManifold, q, p, X, t::Real) = exp!(M, q, p, t * X)

@doc raw"""
    geodesic(M::AbstractManifold, p, X) -> Function

Get the geodesic with initial point `p` and velocity `X` on the [`AbstractManifold`](@ref) `M`.
A geodesic is a curve of zero acceleration. That is for the curve ``γ_{p,X}: I → \mathcal M``,
with ``γ_{p,X}(0) = p`` and ``\dot γ_{p,X}(0) = X`` a geodesic further fulfills

```math
∇_{\dot γ_{p,X}(t)} \dot γ_{p,X}(t) = 0,
```

i.e. the curve is acceleration free with respect to the Riemannian metric.
This yields, that the curve has constant velocity that is locally distance-minimizing.

This function returns a function of (time) `t`.
"""
geodesic(M::AbstractManifold, p, X) = t -> exp(M, p, X, t)
@doc raw"""
    geodesic(M::AbstractManifold, p, X, t::Real)

Evaluate the geodesic ``γ_{p,X}: I → \mathcal M``,
with ``γ_{p,X}(0) = p`` and ``\dot γ_{p,X}(0) = X`` a geodesic further fulfills

```math
∇_{\dot γ_{p,X}(t)} \dot γ_{p,X}(t) = 0,
```

at time `t`.
"""
geodesic(M::AbstractManifold, p, X, t::Real) = exp(M, p, X, t)
@doc raw"""
    geodesic(M::AbstractManifold, p, X, T::AbstractVector) -> AbstractVector

Evaluate the geodesic ``γ_{p,X}: I → \mathcal M``,
with ``γ_{p,X}(0) = p`` and ``\dot γ_{p,X}(0) = X`` a geodesic further fulfills

```math
∇_{\dot γ_{p,X}(t)} \dot γ_{p,X}(t) = 0,
```

at time points `t` from `T`.
"""
geodesic(M::AbstractManifold, p, X, T::AbstractVector) = map(t -> exp(M, p, X, t), T)

@doc raw"""
    geodesic!(M::AbstractManifold, p, X) -> Function

Get the geodesic with initial point `p` and velocity `X` on the [`AbstractManifold`](@ref) `M`.
A geodesic is a curve of zero acceleration. That is for the curve ``γ_{p,X}: I → \mathcal M``,
with ``γ_{p,X}(0) = p`` and ``\dot γ_{p,X}(0) = X`` a geodesic further fulfills

```math
∇_{\dot γ_{p,X}(t)} \dot γ_{p,X}(t) = 0,
```

i.e. the curve is acceleration free with respect to the Riemannian metric.
This yields that the curve has constant velocity and is locally distance-minimizing.

This function returns a function `(q,t)` of (time) `t` that mutates `q``.
"""
geodesic!(M::AbstractManifold, p, X) = (q, t) -> exp!(M, q, p, X, t)
@doc raw"""
    geodesic!(M::AbstractManifold, q, p, X, t::Real)

Get the geodesic with initial point `p` and velocity `X` on the [`AbstractManifold`](@ref) `M`.
A geodesic is a curve of zero acceleration. That is for the curve ``γ_{p,X}: I → \mathcal M``,
with ``γ_{p,X}(0) = p`` and ``\dot γ_{p,X}(0) = X`` a geodesic further fulfills

```math
∇_{\dot γ_{p,X}(t)} \dot γ_{p,X}(t) = 0,
```

i.e. the curve is acceleration free with respect to the Riemannian metric.
This function evaluates the geodeic at `t` in place of `q`.
"""
geodesic!(M::AbstractManifold, q, p, X, t::Real) = exp!(M, q, p, X, t)
@doc raw"""
    geodesic!(M::AbstractManifold, Q, p, X, T::AbstractVector) -> AbstractVector

Get the geodesic with initial point `p` and velocity `X` on the [`AbstractManifold`](@ref) `M`.
A geodesic is a curve of zero acceleration. That is for the curve ``γ_{p,X}: I → \mathcal M``,
with ``γ_{p,X}(0) = p`` and ``\dot γ_{p,X}(0) = X`` a geodesic further fulfills

```math
∇_{\dot γ_{p,X}(t)} \dot γ_{p,X}(t) = 0,
```

i.e. the curve is acceleration free with respect to the Riemannian metric.
This function evaluates the geodeic at time points `t` fom `T` in place of `Q`.
"""
function geodesic!(M::AbstractManifold, Q, p, X, T::AbstractVector)
    for (q, t) in zip(Q, T)
        exp!(M, q, p, X, t)
    end
    return Q
end

"""
    log(M::AbstractManifold, p, q)

Compute the logarithmic map of point `q` at base point `p` on the [`AbstractManifold`](@ref) `M`.
The logarithmic map is the inverse of the [`exp`](@ref)onential map.
Note that the logarithmic map might not be globally defined.

See also [`inverse_retract`](@ref).
"""
function log(M::AbstractManifold, p, q)
    X = allocate_result(M, log, p, q)
    log!(M, X, p, q)
    return X
end

"""
    log!(M::AbstractManifold, X, p, q)

Compute the logarithmic map of point `q` at base point `p` on the [`AbstractManifold`](@ref) `M`.
The result is saved to `X`.
The logarithmic map is the inverse of the [`exp!`](@ref)onential map.
Note that the logarithmic map might not be globally defined.

see also [`log`](@ref) and [`inverse_retract!`](@ref),
"""
log!(M::AbstractManifold, X, p, q)

@doc raw"""
    shortest_geodesic(M::AbstractManifold, p, q) -> Function

Get a [`geodesic`](@ref) $γ_{p,q}(t)$ whose length is the shortest path between the
points `p`and `q`, where $γ_{p,q}(0)=p$ and $γ_{p,q}(1)=q$.
When there are multiple shortest geodesics, a deterministic choice will be returned.

This function returns a function of time, which may be a `Real` or an `AbstractVector`.
"""
shortest_geodesic(M::AbstractManifold, p, q) = geodesic(M, p, log(M, p, q))
@doc raw"""
    shortest_geodesic(M::AabstractManifold, p, q, t::Real)

Evaluate a [`geodesic`](@ref) $γ_{p,q}(t)$ whose length is the shortest path between the
points `p`and `q`, where $γ_{p,q}(0)=p$ and $γ_{p,q}(1)=q$ at time `t`.
When there are multiple shortest geodesics, a deterministic choice will be returned.
"""
shortest_geodesic(M::AbstractManifold, p, q, t::Real) = geodesic(M, p, log(M, p, q), t)
@doc raw"""
    shortest_geodesic(M::AbstractManifold, p, q, T::AbstractVector) -> AbstractVector

Evaluate a [`geodesic`](@ref) $γ_{p,q}(t)$ whose length is the shortest path between the
points `p`and `q`, where $γ_{p,q}(0)=p$ and $γ_{p,q}(1)=q$ at time points `T`.
When there are multiple shortest geodesics, a deterministic choice will be returned.
"""
function shortest_geodesic(M::AbstractManifold, p, q, T::AbstractVector)
    return geodesic(M, p, log(M, p, q), T)
end

@doc raw"""
    shortest_geodesic!(M::AbstractManifold, p, q) -> Function

Get a [`geodesic`](@ref) $γ_{p,q}(t)$ whose length is the shortest path between the
points `p`and `q`, where $γ_{p,q}(0)=p$ and $γ_{p,q}(1)=q$. When there are
multiple shortest geodesics, a deterministic choice will be returned.

This function returns a function `(r,t) -> ... ` of time `t` which works in place of `r`.

Further variants

    shortest_geodesic!(M::AabstractManifold, r, p, q, t::Real)
    shortest_geodesic!(M::AbstractManifold, R, p, q, T::AbstractVector) -> AbstractVector

mutate (and return) the point `r` and the vector of points `R`, respectively,
returning the point at time `t` or points at times `t` in `T` along the shortest [`geodesic`](@ref).
"""
shortest_geodesic!(M::AbstractManifold, p, q) = geodesic!(M, p, log(M, p, q))
@doc raw"""
    shortest_geodesic!(M::AabstractManifold, r, p, q, t::Real)

Evaluate a [`geodesic`](@ref) $γ_{p,q}(t)$ whose length is the shortest path between the
points `p`and `q`, where $γ_{p,q}(0)=p$ and $γ_{p,q}(1)=q$ at `t` in place of `r`.
When there are multiple shortest geodesics, a deterministic choice will be taken.
"""
function shortest_geodesic!(M::AbstractManifold, r, p, q, t::Real)
    return geodesic!(M, r, p, log(M, p, q), t)
end
@doc raw"""
    shortest_geodesic!(M::AbstractManifold, R, p, q, T::AbstractVector) -> AbstractVector

Evaluate a [`geodesic`](@ref) $γ_{p,q}(t)$ whose length is the shortest path between the
points `p`and `q`, where $γ_{p,q}(0)=p$ and $γ_{p,q}(1)=q$ at all `t` from `T` in place of `R`.
When there are multiple shortest geodesics, a deterministic choice will be taken.
"""
function shortest_geodesic!(M::AbstractManifold, R, p, q, T::AbstractVector)
    return geodesic!(M, R, p, log(M, p, q), T)
end


text:
using Swizzles
using Swizzles.EachindexArrays

@testset "EachindexArrays" begin
    I = CartesianIndices((1:5, 1:5))
    tape = []
    casette(_, i) = push!(tape, i)
    Swizzle(casette).(nothing, Tile(2,2).(I))
    @test tape == [CartesianIndex(1, 1), CartesianIndex(2, 1), CartesianIndex(1, 2), CartesianIndex(2, 2), CartesianIndex(3, 1), CartesianIndex(4, 1), CartesianIndex(3, 2), CartesianIndex(4, 2), CartesianIndex(5, 1), CartesianIndex(5, 2), CartesianIndex(1, 3), CartesianIndex(2, 3), CartesianIndex(1, 4), CartesianIndex(2, 4), CartesianIndex(3, 3), CartesianIndex(4, 3), CartesianIndex(3, 4), CartesianIndex(4, 4), CartesianIndex(5, 3), CartesianIndex(5, 4), CartesianIndex(1, 5), CartesianIndex(2, 5), CartesianIndex(3, 5), CartesianIndex(4, 5), CartesianIndex(5, 5)]
end

ext: jl


text:
# This file is a part of Julia. License is MIT: https://julialang.org/license

using Random

@testset "Pair" begin
    p = Pair(10,20)
    @test p == (10=>20)
    @test isequal(p,10=>20)
    @test iterate(p)[1] == 10
    @test iterate(p, iterate(p)[2])[1] == 20
    @test iterate(p, iterate(p, iterate(p)[2])[2]) == nothing
    @test firstindex(p) == 1
    @test lastindex(p) == length(p) == 2
    @test Base.indexed_iterate(p, 1, nothing) == (10,2)
    @test Base.indexed_iterate(p, 2, nothing) == (20,3)
    @test (1=>2) < (2=>3)
    @test (2=>2) < (2=>3)
    @test !((2=>3) < (2=>3))
    @test (2=>3) < (4=>3)
    @test (1=>100) < (4=>1)
    @test p[1] == 10
    @test p[2] == 20
    @test_throws BoundsError p[3]
    @test_throws BoundsError p[false]
    @test p[true] == 10
    @test p[2.0] == 20
    @test p[0x01] == 10
    @test_throws InexactError p[2.3]
    @test first(p) == 10
    @test last(p) == 20
    @test eltype(p) == Int
    @test eltype(4 => 5.6) == Union{Int,Float64}
    @test vcat(1 => 2.0, 1.0 => 2) == [1.0 => 2.0, 1.0 => 2.0]
end

@testset "Dict" begin
    h = Dict()
    for i=1:10000
        h[i] = i+1
    end
    for i=1:10000
        @test (h[i] == i+1)
    end
    for i=1:2:10000
        delete!(h, i)
    end
    for i=1:2:10000
        h[i] = i+1
    end
    for i=1:10000
        @test (h[i] == i+1)
    end
    for i=1:10000
        delete!(h, i)
    end
    @test isempty(h)
    h[77] = 100
    @test h[77] == 100
    for i=1:10000
        h[i] = i+1
    end
    for i=1:2:10000
        delete!(h, i)
    end
    for i=10001:20000
        h[i] = i+1
    end
    for i=2:2:10000
        @test h[i] == i+1
    end
    for i=10000:20000
        @test h[i] == i+1
    end
    h = Dict{Any,Any}("a" => 3)
    @test h["a"] == 3
    h["a","b"] = 4
    @test h["a","b"] == h[("a","b")] == 4
    h["a","b","c"] = 4
    @test h["a","b","c"] == h[("a","b","c")] == 4

    @testset "eltype, keytype and valtype" begin
        @test eltype(h) == Pair{Any,Any}
        @test keytype(h) == Any
        @test valtype(h) == Any

        td = Dict{AbstractString,Float64}()
        @test eltype(td) == Pair{AbstractString,Float64}
        @test keytype(td) == AbstractString
        @test valtype(td) == Float64
        @test keytype(Dict{AbstractString,Float64}) === AbstractString
        @test valtype(Dict{AbstractString,Float64}) === Float64
    end
    # test rethrow of error in ctor
    @test_throws DomainError Dict((sqrt(p[1]), sqrt(p[2])) for p in zip(-1:2, -1:2))
end

let x = Dict(3=>3, 5=>5, 8=>8, 6=>6)
    pop!(x, 5)
    for k in keys(x)
        Dict{Int,Int}(x)
        @test k in [3, 8, 6]
    end
end

let z = Dict()
    get_KeyError = false
    try
        z["a"]
    catch _e123_
        get_KeyError = isa(_e123_,KeyError)
    end
    @test get_KeyError
end

_d = Dict("a"=>0)
@test isa([k for k in filter(x->length(x)==1, collect(keys(_d)))], Vector{String})

@testset "typeof" begin
    d = Dict(((1, 2), (3, 4)))
    @test d[1] === 2
    @test d[3] === 4
    d2 = Dict(1 => 2, 3 => 4)
    d3 = Dict((1 => 2, 3 => 4))
    @test d == d2 == d3
    @test typeof(d) == typeof(d2) == typeof(d3) == Dict{Int,Int}

    d = Dict(((1, 2), (3, "b")))
    @test d[1] === 2
    @test d[3] == "b"
    d2 = Dict(1 => 2, 3 => "b")
    d3 = Dict((1 => 2, 3 => "b"))
    @test d == d2 == d3
    @test typeof(d) == typeof(d2) == typeof(d3) == Dict{Int,Any}

    d = Dict(((1, 2), ("a", 4)))
    @test d[1] === 2
    @test d["a"] === 4
    d2 = Dict(1 => 2, "a" => 4)
    d3 = Dict((1 => 2, "a" => 4))
    @test d == d2 == d3
    @test typeof(d) == typeof(d2) == typeof(d3) == Dict{Any,Int}

    d = Dict(((1, 2), ("a", "b")))
    @test d[1] === 2
    @test d["a"] == "b"
    d2 = Dict(1 => 2, "a" => "b")
    d3 = Dict((1 => 2, "a" => "b"))
    @test d == d2 == d3
    @test typeof(d) == typeof(d2) == typeof(d3) == Dict{Any,Any}
end

@test_throws ArgumentError first(Dict())
@test first(Dict(:f=>2)) == (:f=>2)

@testset "constructing Dicts from iterators" begin
    d = @inferred Dict(i=>i for i=1:3)
    @test isa(d, Dict{Int,Int})
    @test d == Dict(1=>1, 2=>2, 3=>3)
    d = Dict(i==1 ? (1=>2) : (2.0=>3.0) for i=1:2)
    @test isa(d, Dict{Real,Real})
    @test d == Dict{Real,Real}(2.0=>3.0, 1=>2)

    # issue #39117
    @test Dict(t[1]=>t[2] for t in zip((1,"2"), (2,"2"))) == Dict{Any,Any}(1=>2, "2"=>"2")
end

@testset "type of Dict constructed from varargs of Pairs" begin
    @test Dict(1=>1, 2=>2.0) isa Dict{Int,Real}
    @test Dict(1=>1, 2.0=>2) isa Dict{Real,Int}
    @test Dict(1=>1.0, 2.0=>2) isa Dict{Real,Real}

    for T in (Nothing, Missing)
        @test Dict(1=>1, 2=>T()) isa Dict{Int,Union{Int,T}}
        @test Dict(1=>T(), 2=>2) isa Dict{Int,Union{Int,T}}
        @test Dict(1=>1, T()=>2) isa Dict{Union{Int,T},Int}
        @test Dict(T()=>1, 2=>2) isa Dict{Union{Int,T},Int}
    end
end

@test_throws KeyError Dict("a"=>2)[Base.secret_table_token]

@testset "issue #1821" begin
    d = Dict{String, Vector{Int}}()
    d["a"] = [1, 2]
    @test_throws MethodError d["b"] = 1
    @test isa(repr(d), AbstractString)  # check that printable without error
end

@testset "issue #2344" begin
    local bar
    bestkey(d, key) = key
    bestkey(d::AbstractDict{K,V}, key) where {K<:AbstractString,V} = string(key)
    bar(x) = bestkey(x, :y)
    @test bar(Dict(:x => [1,2,5])) == :y
    @test bar(Dict("x" => [1,2,5])) == "y"
end

mutable struct I1438T
    id
end
import Base.hash
hash(x::I1438T, h::UInt) = hash(x.id, h)

@testset "issue #1438" begin
    seq = [26, 28, 29, 30, 31, 32, 33, 34, 35, 36, -32, -35, -34, -28, 37, 38, 39, 40, -30,
           -31, 41, 42, 43, 44, -33, -36, 45, 46, 47, 48, -37, -38, 49, 50, 51, 52, -46, -50, 53]
    xs = [ I1438T(id) for id = 1:53 ]
    s = Set()
    for id in seq
        if id > 0
            x = xs[id]
            push!(s, x)
            @test in(x, s)                 # check that x can be found
        else
            delete!(s, xs[-id])
        end
    end
end

@testset "equality" for eq in (isequal, ==)
    @test  eq(Dict(), Dict())
    @test  eq(Dict(1 => 1), Dict(1 => 1))
    @test !eq(Dict(1 => 1), Dict())
    @test !eq(Dict(1 => 1), Dict(1 => 2))
    @test !eq(Dict(1 => 1), Dict(2 => 1))

    # Generate some data to populate dicts to be compared
    data_in = [ (rand(1:1000), randstring(2)) for _ in 1:1001 ]

    # Populate the first dict
    d1 = Dict{Int, AbstractString}()
    for (k, v) in data_in
        d1[k] = v
    end
    data_in = collect(d1)
    # shuffle the data
    for i in 1:length(data_in)
        j = rand(1:length(data_in))
        data_in[i], data_in[j] = data_in[j], data_in[i]
    end
    # Inserting data in different (shuffled) order should result in
    # equivalent dict.
    d2 = Dict{Int, AbstractString}()
    for (k, v) in data_in
        d2[k] = v
    end

    @test eq(d1, d2)
    d3 = copy(d2)
    d4 = copy(d2)
    # Removing an item gives different dict
    delete!(d1, data_in[rand(1:length(data_in))][1])
    @test !eq(d1, d2)
    # Changing a value gives different dict
    d3[data_in[rand(1:length(data_in))][1]] = randstring(3)
    !eq(d1, d3)
    # Adding a pair gives different dict
    d4[1001] = randstring(3)
    @test !eq(d1, d4)

    @test eq(Dict(), sizehint!(Dict(),96))

    # Dictionaries of different types
    @test !eq(Dict(1 => 2), Dict("dog" => "bone"))
    @test eq(Dict{Int,Int}(), Dict{AbstractString,AbstractString}())
end

@testset "equality special cases" begin
    @test Dict(1=>0.0) == Dict(1=>-0.0)
    @test !isequal(Dict(1=>0.0), Dict(1=>-0.0))

    @test Dict(0.0=>1) != Dict(-0.0=>1)
    @test !isequal(Dict(0.0=>1), Dict(-0.0=>1))

    @test Dict(1=>NaN) != Dict(1=>NaN)
    @test isequal(Dict(1=>NaN), Dict(1=>NaN))

    @test Dict(NaN=>1) == Dict(NaN=>1)
    @test isequal(Dict(NaN=>1), Dict(NaN=>1))

    @test ismissing(Dict(1=>missing) == Dict(1=>missing))
    @test isequal(Dict(1=>missing), Dict(1=>missing))
    d = Dict(1=>missing)
    @test ismissing(d == d)
    d = Dict(1=>[missing])
    @test ismissing(d == d)
    d = Dict(1=>NaN)
    @test d != d
    @test isequal(d, d)

    @test Dict(missing=>1) == Dict(missing=>1)
    @test isequal(Dict(missing=>1), Dict(missing=>1))
end

@testset "get!" begin # (get with default values assigned to the given location)
    f(x) = x^2
    d = Dict(8=>19)
    @test get!(d, 8, 5) == 19
    @test get!(d, 19, 2) == 2

    @test get!(d, 42) do  # d is updated with f(2)
        f(2)
    end == 4

    @test get!(d, 42) do  # d is not updated
        f(200)
    end == 4

    @test get(d, 13) do   # d is not updated
        f(4)
    end == 16

    @test d == Dict(8=>19, 19=>2, 42=>4)
end

@testset "getkey" begin
   h = Dict(1=>2, 3 => 6, 5=>10)
   @test getkey(h, 1, 7) == 1
   @test getkey(h, 4, 6) == 6
   @test getkey(h, "1", 8) == 8
end

@testset "show" begin
    for d in (Dict("\n" => "\n", "1" => "\n", "\n" => "2"),
              Dict(string(i) => i for i = 1:30),
              Dict(reshape(1:i^2,i,i) => reshape(1:i^2,i,i) for i = 1:24),
              Dict(String(Char['α':'α'+i;]) => String(Char['α':'α'+i;]) for i = (1:10)*10),
              Dict("key" => zeros(0, 0)))
        for cols in (12, 40, 80), rows in (2, 10, 24)
            # Ensure output is limited as requested
            s = IOBuffer()
            io = Base.IOContext(s, :limit => true, :displaysize => (rows, cols))
            Base.show(io, MIME("text/plain"), d)
            out = split(String(take!(s)),'\n')
            for line in out[2:end]
                @test textwidth(line) <= cols
            end
            @test length(out) <= rows

            for f in (keys, values)
                s = IOBuffer()
                io = Base.IOContext(s, :limit => true, :displaysize => (rows, cols))
                Base.show(io, MIME("text/plain"), f(d))
                out = split(String(take!(s)),'\n')
                for line in out[2:end]
                    @test textwidth(line) <= cols
                end
                @test length(out) <= rows
            end
        end
        # Simply ensure these do not throw errors
        Base.show(IOBuffer(), d)
        @test !isempty(summary(d))
        @test !isempty(summary(keys(d)))
        @test !isempty(summary(values(d)))
    end
    # show on empty Dict
    io = IOBuffer()
    d = Dict{Int, String}()
    show(io, d)
    str = String(take!(io))
    @test str == "Dict{$(Int), String}()"
    close(io)
end

@testset "Issue #15739" begin # Compact REPL printouts of an `AbstractDict` use brackets when appropriate
    d = Dict((1=>2) => (3=>45), (3=>10) => (10=>11))
    buf = IOBuffer()
    show(IOContext(buf, :compact => true), d)

    # Check explicitly for the expected strings, since the CPU bitness effects
    # dictionary ordering.
    result = String(take!(buf))
    @test occursin("Dict", result)
    @test occursin("(1=>2)=>(3=>45)", result)
    @test occursin("(3=>10)=>(10=>11)", result)
end

mutable struct Alpha end
Base.show(io::IO, ::Alpha) = print(io,"α")
@testset "issue #9463" begin
    sbuff = IOBuffer()
    io = Base.IOContext(sbuff, :limit => true, :displaysize => (10, 20))

    Base.show(io, MIME("text/plain"), Dict(Alpha()=>1))
    local str = String(take!(sbuff))
    @test !occursin("…", str)
    @test endswith(str, "α => 1")
end

@testset "issue #2540" begin
    d = Dict{Any,Any}(Dict(x => 1 for x in ['a', 'b', 'c']))
    @test d == Dict('a'=>1, 'b'=>1, 'c'=> 1)
end

@testset "issue #2629" begin
    d = Dict{AbstractString,AbstractString}(Dict(a=>"foo" for a in ["a","b","c"]))
    @test d == Dict("a"=>"foo","b"=>"foo","c"=>"foo")
end

@testset "issue #5886" begin
    d5886 = Dict()
    for k5886 in 1:11
       d5886[k5886] = 1
    end
    for k5886 in keys(d5886)
       # undefined ref if not fixed
       d5886[k5886] += 1
    end
end

@testset "issue #8877" begin
    a = Dict("foo" => 0.0, "bar" => 42.0)
    b = Dict("フー" => 17, "バー" => 4711)
    @test typeof(merge(a, b)) === Dict{String,Float64}
end

@testset "issue 9295" begin
    d = Dict()
    @test push!(d, 'a' => 1) === d
    @test d['a'] == 1
    @test push!(d, 'b' => 2, 'c' => 3) === d
    @test d['b'] == 2
    @test d['c'] == 3
    @test push!(d, 'd' => 4, 'e' => 5, 'f' => 6) === d
    @test d['d'] == 4
    @test d['e'] == 5
    @test d['f'] == 6
    @test length(d) == 6
end

mutable struct T10647{T}; x::T; end
@testset "issue #10647" begin
    a = IdDict()
    a[1] = a
    a[a] = 2
    a[3] = T10647(a)
    @test isequal(a, a)
    show(IOBuffer(), a)
    Base.show(Base.IOContext(IOBuffer(), :limit => true), a)
    Base.show(IOBuffer(), a)
    Base.show(Base.IOContext(IOBuffer(), :limit => true), a)
end

@testset "IdDict{Any,Any} and partial inference" begin
    a = IdDict{Any,Any}()
    a[1] = a
    a[a] = 2

    sa = empty(a)
    @test isempty(sa)
    @test isa(sa, IdDict{Any,Any})

    @test length(a) == 2
    @test 1 in keys(a)
    @test a in keys(a)
    @test a[1] === a
    @test a[a] === 2

    ca = copy(a)
    @test length(ca) == length(a)
    @test isequal(ca, a)
    @test ca !== a # make sure they are different objects

    ca = empty!(ca)
    @test length(ca) == 0
    @test length(a) == 2

    d = Dict('a'=>1, 'b'=>1, 'c'=> 3)
    @test a != d
    @test !isequal(a, d)

    @test length(IdDict{Any,Any}(1=>2, 1.0=>3)) == 2
    @test length(Dict(1=>2, 1.0=>3)) == 1

    d = @inferred IdDict{Any,Any}(i=>i for i=1:3)
    @test isa(d, IdDict{Any,Any})
    @test d == IdDict{Any,Any}(1=>1, 2=>2, 3=>3)

    d = @inferred IdDict{Any,Any}(Pair(1,1), Pair(2,2), Pair(3,3))
    @test isa(d, IdDict{Any,Any})
    @test d == IdDict{Any,Any}(1=>1, 2=>2, 3=>3)
    @test eltype(d) == Pair{Any,Any}

    d = IdDict{Any,Int32}(:hi => 7)
    let c = Ref{Any}(1.5)
        f() = c[]
        @test @inferred(get!(f, d, :hi)) === Int32(7)
        @test_throws InexactError(:Int32, Int32, 1.5) get!(f, d, :hello)
    end
end

@testset "IdDict" begin
    a = IdDict()
    a[1] = a
    a[a] = 2

    sa = empty(a)
    @test isempty(sa)
    @test isa(sa, IdDict)

    @test length(a) == 2
    @test 1 in keys(a)
    @test a in keys(a)
    @test a[1] === a
    @test a[a] === 2

    ca = copy(a)
    @test length(ca) == length(a)
    @test isequal(ca, a)
    @test ca !== a # make sure they are different objects

    ca = empty!(ca)
    @test length(ca) == 0
    @test length(a) == 2

    d = Dict('a'=>1, 'b'=>1, 'c'=> 3)
    @test a != d
    @test !isequal(a, d)

    @test length(IdDict(1=>2, 1.0=>3)) == 2
    @test length(Dict(1=>2, 1.0=>3)) == 1

    d = @inferred IdDict(i=>i for i=1:3)
    @test isa(d, IdDict)
    @test d == IdDict(1=>1, 2=>2, 3=>3)

    d = @inferred IdDict(Pair(1,1), Pair(2,2), Pair(3,3))
    @test isa(d, IdDict)
    @test d == IdDict(1=>1, 2=>2, 3=>3)
    @test eltype(d) == Pair{Int,Int}
    @test_throws KeyError d[:a]
    @test_throws ArgumentError d[:a] = 1
    @test_throws MethodError d[1] = :a

    # copy constructor
    d = IdDict(Pair(1,1), Pair(2,2), Pair(3,3))
    @test collect(values(IdDict{Int,Float64}(d))) == collect(values(d))
    @test_throws ArgumentError IdDict{Float64,Int}(d)

    # misc constructors
    @test typeof(IdDict(1=>1, :a=>2)) == IdDict{Any,Int}
    @test typeof(IdDict(1=>1, 1=>:a)) == IdDict{Int,Any}
    @test typeof(IdDict(:a=>1, 1=>:a)) == IdDict{Any,Any}
    @test typeof(IdDict(())) == IdDict{Any,Any}

    # check that returned values are inferred
    d = @inferred IdDict(Pair(1,1), Pair(2,2), Pair(3,3))
    @test 1 == @inferred d[1]
    @inferred setindex!(d, -1, 10)
    @test d[10] == -1
    @test 1 == @inferred d[1]
    @test get(d, -111, nothing) == nothing
    @test 1 == @inferred get(d, 1, 1)
    @test pop!(d, -111, nothing) == nothing
    @test 1 == @inferred pop!(d, 1)

    # get! and delete!
    d = @inferred IdDict(Pair(:a,1), Pair(:b,2), Pair(3,3))
    @test get!(d, "a", -1) == -1
    @test d["a"] == -1
    @test get!(d, "a", "b") == -1
    @test_throws MethodError get!(d, "b", "b")
    @test delete!(d, "a") === d
    @test !haskey(d, "a")
    @test_throws ArgumentError get!(IdDict{Symbol,Any}(), 2, "b")
    @test get!(IdDict{Int,Int}(), 1, 2.0) === 2
    @test get!(()->2.0, IdDict{Int,Int}(), 1) === 2

    # sizehint! & rehash!
    d = IdDict()
    @test sizehint!(d, 10^4) === d
    @test length(d.ht) >= 10^4
    d = IdDict()
    for jj=1:30, i=1:10^4
        d[i] = i
    end
    for i=1:10^4
        @test d[i] == i
    end
    @test length(d.ht) >= 10^4
    @test d === Base.rehash!(d, 123452) # number needs to be even

    # filter!
    d = IdDict(1=>1, 2=>3, 3=>2)
    filter!(x->isodd(x[2]), d)
    @test d[1] == 1
    @test d[2] == 3
    @test !haskey(d, 3)

    # not an iterator of tuples or pairs
    @test_throws ArgumentError IdDict([1, 2, 3, 4])
    # test rethrow of error in ctor
    @test_throws DomainError   IdDict((sqrt(p[1]), sqrt(p[2])) for p in zip(-1:2, -1:2))
end

@testset "issue 30165, get! for IdDict" begin
    f(x) = x^2
    d = IdDict(8=>19)
    @test get!(d, 8, 5) == 19
    @test get!(d, 19, 2) == 2

    @test get!(d, 42) do  # d is updated with f(2)
        f(2)
    end == 4

    @test get!(d, 42) do  # d is not updated
        f(200)
    end == 4

    @test get(d, 13) do   # d is not updated
        f(4)
    end == 16

    @test d == IdDict(8=>19, 19=>2, 42=>4)
end

@testset "issue #26833, deletion from IdDict" begin
    d = IdDict()
    i = 1
    # generate many hash collisions
    while length(d) < 32 # expected to occur at i <≈ 2^16 * 2^5
        if objectid(i) % UInt16 == 0x1111
            push!(d, i => true)
        end
        i += 1
    end
    k = collect(keys(d))
    @test haskey(d, k[1])
    delete!(d, k[1])
    @test length(d) == 31
    @test !haskey(d, k[1])
    @test haskey(d, k[end])
    push!(d, k[end] => false)
    @test length(d) == 31
    @test haskey(d, k[end])
    @test !pop!(d, k[end])
    @test !haskey(d, k[end])
    @test length(d) == 30
end

@testset "Issue #7944" begin
    d = Dict{Int,Int}()
    get!(d, 0) do
        d[0] = 1
    end
    @test length(d) == 1
end

@testset "iteration" begin
    d = Dict('a'=>1, 'b'=>1, 'c'=> 3)
    @test [d[k] for k in keys(d)] == [d[k] for k in eachindex(d)] ==
          [v for (k, v) in d] == [d[x[1]] for (i, x) in enumerate(d)]
end

@testset "generators, similar" begin
    d = Dict(:a=>"a")
    # TODO: restore when 0.7 deprecation is removed
    #@test @inferred(map(identity, d)) == d
end

@testset "Issue 12451" begin
    @test_throws ArgumentError Dict(0)
    @test_throws ArgumentError Dict([1])
    @test_throws ArgumentError Dict([(1,2),0])
end

# test Dict constructor's argument checking (for an iterable of pairs or tuples)
# make sure other errors can propagate when the nature of the iterator is not the problem
@test_throws InexactError Dict(convert(Int,1.5) for i=1:1)
@test_throws InexactError WeakKeyDict(convert(Int,1.5) for i=1:1)

import Base.ImmutableDict
@testset "ImmutableDict" begin
    d = ImmutableDict{String, String}()
    k1 = "key1"
    k2 = "key2"
    v1 = "value1"
    v2 = "value2"
    d1 = ImmutableDict(d, k1 => v1)
    d2 = ImmutableDict(d1, k2 => v2)
    d3 = ImmutableDict(d2, k1 => v2)
    d4 = ImmutableDict(d3, k2 => v1)
    dnan = ImmutableDict{String, Float64}(k2, NaN)
    dnum = ImmutableDict(dnan, k2 => 1)
    f(x) = x^2

    @test isempty(collect(d))
    @test !isempty(collect(d1))
    @test isempty(d)
    @test !isempty(d1)
    @test length(d) == 0
    @test length(d1) == 1
    @test length(d2) == 2
    @test length(d3) == 3
    @test length(d4) == 4
    @test !(k1 in keys(d))
    @test k1 in keys(d1)
    @test k1 in keys(d2)
    @test k1 in keys(d3)
    @test k1 in keys(d4)

    @test !haskey(d, k1)
    @test haskey(d1, k1)
    @test haskey(d2, k1)
    @test haskey(d3, k1)
    @test haskey(d4, k1)
    @test !(k2 in keys(d1))
    @test k2 in keys(d2)
    @test !(k1 in values(d4))
    @test v1 in values(d4)
    @test collect(d1) == [Pair(k1, v1)]
    @test collect(d4) == reverse([Pair(k1, v1), Pair(k2, v2), Pair(k1, v2), Pair(k2, v1)])
    @test d1 == ImmutableDict(d, k1 => v1)
    @test !((k1 => v2) in d2)
    @test (k1 => v2) in d3
    @test (k1 => v1) in d4
    @test (k1 => v2) in d4
    @test in(k2 => "value2", d4, ===)
    @test in(k2 => v2, d4, ===)
    @test in(k2 => NaN, dnan, isequal)
    @test in(k2 => NaN, dnan, ===)
    @test !in(k2 => NaN, dnan, ==)
    @test !in(k2 => 1, dnum, ===)
    @test in(k2 => 1.0, dnum, ===)
    @test !in(k2 => 1, dnum, <)
    @test in(k2 => 0, dnum, <)
    @test get(d1, "key1", :default) === v1
    @test get(d4, "key1", :default) === v2
    @test get(d4, "foo", :default) === :default
    @test get(d, k1, :default) === :default
    @test get(d1, "key1") do
        f(2)
    end === v1
    @test get(d4, "key1") do
        f(4)
    end === v2
    @test get(d4, "foo") do
        f(6)
    end === 36
    @test get(d, k1) do
        f(8)
    end === 64
    @test d1["key1"] === v1
    @test d4["key1"] === v2
    @test empty(d3) === d
    @test empty(d) === d

    @test_throws KeyError d[k1]
    @test_throws KeyError d1["key2"]

    v = [k1 => v1, k2 => v2]
    d5 = ImmutableDict(v...)
    @test d5 == d2
    @test reverse(collect(d5)) == v
    d6 = ImmutableDict(:a => 1, :b => 3, :a => 2)
    @test d6[:a] == 2
    @test d6[:b] == 3

    @test !haskey(ImmutableDict(-0.0=>1), 0.0)
end

@testset "filtering" begin
    d = Dict(zip(1:1000,1:1000))
    f = p -> iseven(p.first)
    @test filter(f, d) == filter!(f, copy(d)) ==
          invoke(filter!, Tuple{Function,AbstractDict}, f, copy(d)) ==
          Dict(zip(2:2:1000, 2:2:1000))
    d = Dict(zip(-1:3,-1:3))
    f = p -> sqrt(p.second) > 2
    # test rethrowing error from f
    @test_throws DomainError filter(f, d)
end

struct MyString <: AbstractString
    str::String
end
struct MyInt <: Integer
    val::UInt
end

import Base.==
const global hashoffset = [UInt(190)]

Base.hash(s::MyString) = hash(s.str) + hashoffset[]
Base.lastindex(s::MyString) = lastindex(s.str)
Base.iterate(s::MyString, v::Int=1) = iterate(s.str, v)
Base.isequal(a::MyString, b::MyString) = isequal(a.str, b.str)
==(a::MyString, b::MyString) = (a.str == b.str)

Base.hash(v::MyInt) = v.val + hashoffset[]
Base.lastindex(v::MyInt) = lastindex(v.val)
Base.iterate(v::MyInt, i...) = iterate(v.val, i...)
Base.isequal(a::MyInt, b::MyInt) = isequal(a.val, b.val)
==(a::MyInt, b::MyInt) = (a.val == b.val)
@testset "issue #15077" begin
    let badKeys = [
        "FINO_emv5.0","FINO_ema0.1","RATE_ema1.0","NIBPM_ema1.0",
        "SAO2_emv5.0","O2FLOW_ema5.0","preop_Neuro/Psych_","gender_",
        "FIO2_ema0.1","PEAK_ema5.0","preop_Reproductive_denies","O2FLOW_ema0.1",
        "preop_Endocrine_denies","preop_Respiratory_",
        "NIBPM_ema0.1","PROPOFOL_MCG/KG/MIN_decay5.0","NIBPD_ema1.0","NIBPS_ema5.0",
        "anesthesiaStartTime","NIBPS_ema1.0","RESPRATE_ema1.0","PEAK_ema0.1",
        "preop_GU_denies","preop_Cardiovascular_","PIP_ema5.0","preop_ENT_denies",
        "preop_Skin_denies","preop_Renal_denies","asaCode_IIIE","N2OFLOW_emv5.0",
        "NIBPD_emv5.0", # <--- here is the key that we later can't find
        "NIBPM_ema5.0","preop_Respiratory_complete","ETCO2_ema5.0",
        "RESPRATE_ema0.1","preop_Functional Status_<2","preop_Renal_symptoms",
        "ECGRATE_ema5.0","FIO2_emv5.0","RESPRATE_emv5.0","7wu3ty0a4fs","BVO",
        "4UrCWXUsaT"
    ]
        local d = Dict{AbstractString,Int}()
        for i = 1:length(badKeys)
            d[badKeys[i]] = i
        end
        # Check all keys for missing values
        for i = 1:length(badKeys)
            @test d[badKeys[i]] == i
        end

        # Walk through all possible hash values (mod size of hash table)
        for offset = 0:1023
            local d2 = Dict{MyString,Int}()
            hashoffset[] = offset
            for i = 1:length(badKeys)
                d2[MyString(badKeys[i])] = i
            end
            # Check all keys for missing values
            for i = 1:length(badKeys)
                @test d2[MyString(badKeys[i])] == i
            end
        end
    end

    let badKeys = UInt16[0xb800,0xa501,0xcdff,0x6303,0xe40a,0xcf0e,0xf3df,0xae99,0x9913,0x741c,
                         0xd01f,0xc822,0x9723,0xb7a0,0xea25,0x7423,0x6029,0x202a,0x822b,0x492c,
                         0xd02c,0x862d,0x8f34,0xe529,0xf938,0x4f39,0xd03a,0x473b,0x1e3b,0x1d3a,
                         0xcc39,0x7339,0xcf40,0x8740,0x813d,0xe640,0xc443,0x6344,0x3744,0x2c3d,
                         0x8c48,0xdf49,0x5743]
        # Walk through all possible hash values (mod size of hash table)
        for offset = 0:1023
            local d2 = Dict{MyInt, Int}()
            hashoffset[] = offset
            for i = 1:length(badKeys)
                d2[MyInt(badKeys[i])] = i
            end
            # Check all keys for missing values
            for i = 1:length(badKeys)
                @test d2[MyInt(badKeys[i])] == i
            end
        end
    end
end

# #18213
Dict(1 => rand(2,3), 'c' => "asdf") # just make sure this does not trigger a deprecation

@testset "WeakKeyDict" begin
    A = [1]
    B = [2]
    C = [3]

    # construction
    wkd = WeakKeyDict()
    wkd[A] = 2
    wkd[B] = 3
    wkd[C] = 4
    dd = convert(Dict{Any,Any},wkd)
    @test WeakKeyDict(dd) == wkd
    @test convert(WeakKeyDict{Any, Any}, dd) == wkd
    @test isa(WeakKeyDict(dd), WeakKeyDict{Any,Any})
    @test WeakKeyDict(A=>2, B=>3, C=>4) == wkd
    @test isa(WeakKeyDict(A=>2, B=>3, C=>4), WeakKeyDict{Array{Int,1},Int})
    @test WeakKeyDict(a=>i+1 for (i,a) in enumerate([A,B,C]) ) == wkd
    @test WeakKeyDict([(A,2), (B,3), (C,4)]) == wkd
    @test WeakKeyDict{typeof(A), Int64}(Pair(A,2), Pair(B,3), Pair(C,4)) == wkd
    @test WeakKeyDict(Pair(A,2), Pair(B,3), Pair(C,4)) == wkd
    D = [[4.0]]
    @test WeakKeyDict(Pair(A,2), Pair(B,3), Pair(D,4.0)) isa WeakKeyDict{Any, Any}
    @test isa(WeakKeyDict(Pair(A,2), Pair(B,3.0), Pair(C,4)), WeakKeyDict{Array{Int,1},Any})
    @test isa(WeakKeyDict(Pair(convert(Vector{Number}, A),2), Pair(B,3), Pair(C,4)), WeakKeyDict{Any,Int})
    @test copy(wkd) == wkd

    @test length(wkd) == 3
    @test !isempty(wkd)
    res = pop!(wkd, C)
    @test res == 4
    @test length(wkd) == 2
    res = pop!(wkd, C, 3)
    @test res == 3
    @test C ∉ keys(wkd)
    @test 4 ∉ values(wkd)
    @test length(wkd) == 2
    @test !isempty(wkd)
    wkd = filter!( p -> p.first != B, wkd)
    @test B ∉ keys(wkd)
    @test 3 ∉ values(wkd)
    @test length(wkd) == 1
    @test WeakKeyDict(Pair(A, 2)) == wkd
    @test !isempty(wkd)

    wkd = empty!(wkd)
    @test wkd == empty(wkd)
    @test typeof(wkd) == typeof(empty(wkd))
    @test length(wkd) == 0
    @test isempty(wkd)
    @test isa(wkd, WeakKeyDict)

    @test_throws ArgumentError WeakKeyDict([1, 2, 3])

    wkd = WeakKeyDict(A=>1)
    @test delete!(wkd, A) == empty(wkd)
    @test delete!(wkd, A) === wkd

    # issue #26939
    d26939 = WeakKeyDict()
    (@noinline d -> d[big"1.0" + 1.1] = 1)(d26939)
    GC.gc() # primarily to make sure this doesn't segfault
    @test count(d26939) == 0
    @test length(d26939.ht) == 1
    @test length(d26939) == 0
    @test isempty(d26939)
    empty!(d26939)
    for i in 1:8
        (@noinline (d, i) -> d[big(i + 12345)] = 1)(d26939, i)
    end
    lock(GC.gc, d26939)
    @test length(d26939.ht) == 8
    @test count(d26939) == 0
    @test !haskey(d26939, nothing)
    @test_throws KeyError(nothing) d26939[nothing]
    @test_throws KeyError(nothing) get(d26939, nothing, 1)
    @test_throws KeyError(nothing) get(() -> 1, d26939, nothing)
    @test_throws KeyError(nothing) pop!(d26939, nothing)
    @test getkey(d26939, nothing, 321) === 321
    @test pop!(d26939, nothing, 321) === 321
    @test delete!(d26939, nothing) === d26939
    @test length(d26939.ht) == 8
    @test_throws ArgumentError d26939[nothing] = 1
    @test_throws ArgumentError get!(d26939, nothing, 1)
    @test_throws ArgumentError get!(() -> 1, d26939, nothing)
    @test isempty(d26939)
    @test length(d26939.ht) == 0
    @test length(d26939) == 0

    # WeakKeyDict does not convert keys on setting
    @test_throws ArgumentError WeakKeyDict{Vector{Int},Any}([5.0]=>1)
    wkd = WeakKeyDict(A=>2)
    @test_throws ArgumentError get!(wkd, [2.0], 2)
    @test get!(wkd, [1.0], 2) === 2

    # WeakKeyDict does convert on getting
    wkd = WeakKeyDict(A=>2)
    @test keytype(wkd)==Vector{Int}
    @test wkd[[1.0]] == 2
    @test haskey(wkd, [1.0])
    @test pop!(wkd, [1.0]) == 2
    @test get(()->3, wkd, [2.0]) == 3

    # map! on values of WKD
    wkd = WeakKeyDict(A=>2, B=>3)
    map!(v -> v-1, values(wkd))
    @test wkd == WeakKeyDict(A=>1, B=>2)

    # get!
    wkd = WeakKeyDict(A=>2)
    @test get!(wkd, B, 3) == 3
    @test wkd == WeakKeyDict(A=>2, B=>3)
    @test get!(()->4, wkd, C) == 4
    @test wkd == WeakKeyDict(A=>2, B=>3, C=>4)
    @test get!(()->5, wkd, [1.0]) == 2

    GC.@preserve A B C D nothing
end

@testset "issue #19995, hash of dicts" begin
    @test hash(Dict(Dict(1=>2) => 3, Dict(4=>5) => 6)) != hash(Dict(Dict(4=>5) => 3, Dict(1=>2) => 6))
    a = Dict(Dict(3 => 4, 2 => 3) => 2, Dict(1 => 2, 5 => 6) => 1)
    b = Dict(Dict(1 => 2, 2 => 3, 5 => 6) => 1, Dict(3 => 4) => 2)
    @test hash(a) != hash(b)
end

mutable struct Foo_15776
    x::Vector{Pair{Tuple{Function, Vararg{Int}}, Int}}
end
@testset "issue #15776, convert for pair" begin
    z = [Pair((+,1,5,7), 3), Pair((-,6,5,3,5,8), 1)]
    f = Foo_15776(z)
    @test f.x[1].first == (+, 1, 5, 7)
    @test f.x[1].second == 3
    @test f.x[2].first == (-, 6, 5, 3, 5, 8)
    @test f.x[2].second == 1
end

@testset "issue #18708 error type for dict constructor" begin
    @test_throws UndefVarError Dict(x => y for x in 1:10)
end

mutable struct Error19179 <: Exception
end

@testset "issue #19179 throwing error in dict constructor" begin
    @test_throws Error19179 Dict(i => throw(Error19179()) for i in 1:10)
end

# issue #18090
let
    d = Dict(i => i^2 for i in 1:10_000)
    z = zip(keys(d), values(d))
    for (pair, tupl) in zip(d, z)
        @test pair[1] == tupl[1] && pair[2] == tupl[2]
    end
end

struct NonFunctionCallable end
(::NonFunctionCallable)(args...) = +(args...)

@testset "Dict merge" begin
    d1 = Dict("A" => 1, "B" => 2)
    d2 = Dict("B" => 3.0, "C" => 4.0)
    @test @inferred merge(d1, d2) == Dict("A" => 1, "B" => 3, "C" => 4)
    # merge with combiner function
    @test @inferred mergewith(+, d1, d2) == Dict("A" => 1, "B" => 5, "C" => 4)
    @test @inferred mergewith(*, d1, d2) == Dict("A" => 1, "B" => 6, "C" => 4)
    @test @inferred mergewith(-, d1, d2) == Dict("A" => 1, "B" => -1, "C" => 4)
    @test @inferred mergewith(NonFunctionCallable(), d1, d2) == Dict("A" => 1, "B" => 5, "C" => 4)
    @test foldl(mergewith(+), [d1, d2]; init=Dict{Union{},Union{}}()) ==
        Dict("A" => 1, "B" => 5, "C" => 4)
    # backward compatibility
    @test @inferred merge(+, d1, d2) == Dict("A" => 1, "B" => 5, "C" => 4)
end

@testset "Dict merge!" begin
    d1 = Dict("A" => 1, "B" => 2)
    d2 = Dict("B" => 3, "C" => 4)
    @inferred merge!(d1, d2)
    @test d1 == Dict("A" => 1, "B" => 3, "C" => 4)
    # merge! with combiner function
    @inferred mergewith!(+, d1, d2)
    @test d1 == Dict("A" => 1, "B" => 6, "C" => 8)
    @inferred mergewith!(*, d1, d2)
    @test d1 == Dict("A" => 1, "B" => 18, "C" => 32)
    @inferred mergewith!(-, d1, d2)
    @test d1 == Dict("A" => 1, "B" => 15, "C" => 28)
    @inferred mergewith!(NonFunctionCallable(), d1, d2)
    @test d1 == Dict("A" => 1, "B" => 18, "C" => 32)
    @test foldl(mergewith!(+), [d1, d2]; init=empty(d1)) ==
        Dict("A" => 1, "B" => 21, "C" => 36)
    # backward compatibility
    merge!(+, d1, d2)
    @test d1 == Dict("A" => 1, "B" => 21, "C" => 36)
end

@testset "Dict reduce merge" begin
    function check_merge(i::Vector{<:Dict}, o)
        r1 = reduce(merge, i)
        r2 = merge(i...)
        t = typeof(o)
        @test r1 == o
        @test r2 == o
        @test typeof(r1) == t
        @test typeof(r2) == t
    end
    check_merge([Dict(1=>2), Dict(1.0=>2.0)], Dict(1.0=>2.0))
    check_merge([Dict(1=>2), Dict(2=>Complex(1.0, 1.0))],
      Dict(2=>Complex(1.0, 1.0), 1=>Complex(2.0, 0.0)))
    check_merge([Dict(1=>2), Dict(3=>4)], Dict(3=>4, 1=>2))
    check_merge([Dict(3=>4), Dict(:a=>5)], Dict(:a => 5, 3 => 4))
end

@testset "AbstractDict mergewith!" begin
# we use IdDict to test the mergewith! implementation for AbstractDict
    d1 = IdDict(1 => 1, 2 => 2)
    d2 = IdDict(2 => 3, 3 => 4)
    d3 = IdDict{Int, Float64}(1 => 5, 3 => 6)
    d = copy(d1)
    @inferred mergewith!(-, d, d2)
    @test d == IdDict(1 => 1, 2 => -1, 3 => 4)
    d = copy(d1)
    @inferred mergewith!(-, d, d3)
    @test d == IdDict(1 => -4, 2 => 2, 3 => 6)
    d = copy(d1)
    @inferred mergewith!(+, d, d2, d3)
    @test d == IdDict(1 => 6, 2 => 5, 3 => 10)
    @inferred mergewith(+, d1, d2, d3)
    d = mergewith(+, d1, d2, d3)
    @test d isa Dict{Int, Float64}
    @test d == Dict(1 => 6, 2 => 5, 3 => 10)
end

@testset "misc error/io" begin
    d = Dict('a'=>1, 'b'=>1, 'c'=> 3)
    @test_throws ErrorException 'a' in d
    key_str = sprint(show, keys(d))
    @test 'a' ∈ key_str
    @test 'b' ∈ key_str
    @test 'c' ∈ key_str
end

@testset "Dict pop!" begin
    d = Dict(1=>2, 3=>4)
    @test pop!(d, 1) == 2
    @test_throws KeyError pop!(d, 1)
    @test pop!(d, 1, 0) == 0
    @test pop!(d) == (3=>4)
    @test_throws ArgumentError pop!(d)
end

@testset "keys as a set" begin
    d = Dict(1=>2, 3=>4)
    @test keys(d) isa AbstractSet
    @test empty(keys(d)) isa AbstractSet
    let i = keys(d) ∩ Set([1,2])
        @test i isa AbstractSet
        @test i == Set([1])
    end
    @test Set(string(k) for k in keys(d)) == Set(["1","3"])
end

@testset "find" begin
    @test findall(isequal(1), Dict(:a=>1, :b=>2)) == [:a]
    @test sort(findall(isequal(1), Dict(:a=>1, :b=>1))) == [:a, :b]
    @test isempty(findall(isequal(1), Dict()))
    @test isempty(findall(isequal(1), Dict(:a=>2, :b=>3)))

    @test findfirst(isequal(1), Dict(:a=>1, :b=>2)) == :a
    @test findfirst(isequal(1), Dict(:a=>1, :b=>1, :c=>3)) in (:a, :b)
    @test findfirst(isequal(1), Dict()) === nothing
    @test findfirst(isequal(1), Dict(:a=>2, :b=>3)) === nothing
end

@testset "Dict printing with limited rows" begin
    local buf
    buf = IOBuffer()
    io = IOContext(buf, :displaysize => (4, 80), :limit => true)
    d = Base.ImmutableDict(1=>2)
    show(io, MIME"text/plain"(), d)
    @test String(take!(buf)) == "Base.ImmutableDict{$Int, $Int} with 1 entry: …"
    show(io, MIME"text/plain"(), keys(d))
    @test String(take!(buf)) ==
        "KeySet for a Base.ImmutableDict{$Int, $Int} with 1 entry. Keys: …"

    io = IOContext(io, :displaysize => (5, 80))
    show(io, MIME"text/plain"(), d)
    @test String(take!(buf)) == "Base.ImmutableDict{$Int, $Int} with 1 entry:\n  1 => 2"
    show(io, MIME"text/plain"(), keys(d))
    @test String(take!(buf)) ==
        "KeySet for a Base.ImmutableDict{$Int, $Int} with 1 entry. Keys:\n  1"
    d = Base.ImmutableDict(d, 3=>4)
    show(io, MIME"text/plain"(), d)
    @test String(take!(buf)) == "Base.ImmutableDict{$Int, $Int} with 2 entries:\n  ⋮ => ⋮"
    show(io, MIME"text/plain"(), keys(d))
    @test String(take!(buf)) ==
        "KeySet for a Base.ImmutableDict{$Int, $Int} with 2 entries. Keys:\n  ⋮"

    io = IOContext(io, :displaysize => (6, 80))
    show(io, MIME"text/plain"(), d)
    @test String(take!(buf)) ==
        "Base.ImmutableDict{$Int, $Int} with 2 entries:\n  3 => 4\n  1 => 2"
    show(io, MIME"text/plain"(), keys(d))
    @test String(take!(buf)) ==
        "KeySet for a Base.ImmutableDict{$Int, $Int} with 2 entries. Keys:\n  3\n  1"
    d = Base.ImmutableDict(d, 5=>6)
    show(io, MIME"text/plain"(), d)
    @test String(take!(buf)) ==
        "Base.ImmutableDict{$Int, $Int} with 3 entries:\n  5 => 6\n  ⋮ => ⋮"
    show(io, MIME"text/plain"(), keys(d))
    @test String(take!(buf)) ==
        "KeySet for a Base.ImmutableDict{$Int, $Int} with 3 entries. Keys:\n  5\n  ⋮"
end

@testset "copy!" begin
    s = Dict(1=>2, 2=>3)
    for a = ([3=>4], [0x3=>0x4], [3=>4, 5=>6, 7=>8], Pair{UInt,UInt}[3=>4, 5=>6, 7=>8])
        @test s === copy!(s, Dict(a)) == Dict(a)
        if length(a) == 1 # current limitation of Base.ImmutableDict
            @test s === copy!(s, Base.ImmutableDict(a[])) == Dict(a[])
        end
    end
end

@testset "map!(f, values(dict))" begin
    @testset "AbstractDict & Fallback" begin
        mutable struct TestDict{K, V}  <: AbstractDict{K, V}
            dict::Dict{K, V}
            function TestDict(args...)
                d = Dict(args...)
                new{keytype(d), valtype(d)}(d)
            end
        end
        Base.setindex!(td::TestDict, args...) = setindex!(td.dict, args...)
        Base.getindex(td::TestDict, args...) = getindex(td.dict, args...)
        Base.pairs(D::TestDict) = pairs(D.dict)
        testdict = TestDict(:a=>1, :b=>2)
        map!(v->v-1, values(testdict))
        @test testdict[:a] == 0
        @test testdict[:b] == 1
    end
    @testset "Dict" begin
        testdict = Dict(:a=>1, :b=>2)
        map!(v->v-1, values(testdict))
        @test testdict[:a] == 0
        @test testdict[:b] == 1
    end
end

# WeakKeyDict soundness (#38727)
mutable struct ComparesWithGC38727
    i::Int
end
const armed = Ref{Bool}(true)
@noinline fwdab38727(a, b) = invoke(Base.isequal, Tuple{Any, WeakRef}, a, b)
function Base.isequal(a::ComparesWithGC38727, b::WeakRef)
    # This GC.gc() here simulates a GC during compilation in the original issue
    armed[] && GC.gc()
    armed[] = false
    fwdab38727(a, b)
end
Base.isequal(a::WeakRef, b::ComparesWithGC38727) = isequal(b, a)
Base.:(==)(a::ComparesWithGC38727, b::ComparesWithGC38727) = a.i == b.i
Base.hash(a::ComparesWithGC38727, u::UInt) = Base.hash(a.i, u)
function make_cwgc38727(wkd, i)
    f = ComparesWithGC38727(i)
    function fin(f)
        f.i = -1
    end
    finalizer(fin, f)
    f
end
@noinline mk38727(wkd) = wkd[make_cwgc38727(wkd, 1)] = nothing
function bar()
    wkd = WeakKeyDict{Any, Nothing}()
    mk38727(wkd)
    armed[] = true
    z = getkey(wkd, ComparesWithGC38727(1), missing)
end
# Run this twice, in case compilation the first time around
# masks something.
let c = bar()
    @test c === missing || c == ComparesWithGC38727(1)
end
let c = bar()
    @test c === missing || c == ComparesWithGC38727(1)
end

max_stars_repo_name: jonas-schulze/julia

max_issues_repo_name: jonas-schulze/julia

max_forks_repo_name: jonas-schulze/julia


text:
# 某个时期三国态势

module 魏
  king = "曹操" # 这个king模块魏的全局变量
  prince = "曹丕"
end

module 蜀
  king = "刘备"
  module 荆
    commander = "关羽"
  end
  cmdrJing = 荆.commander # 直接可访问到嵌套模块（全局作用域）荆（并通过合法的点注解访问荆模块的commander变量
  import ..魏 # 导入模块魏
  enemy = 魏.king # 可通过合法的点注解访问魏模块的king变量
end

module 吴
  king = "孙权"
  partner = prince # 未定义prince符号（UndefVarError: prince not defined）
  brotherInLaw = 蜀.king # 未定义蜀符号（更不用提其king符号）（UndefVarError: 蜀 not defined）
end

module 汉
  emperor = "刘协"
  import ..蜀
  蜀.king *= "：皇叔-左将军-豫州牧" # 不能修改别的模块的变量（ERROR: LoadError: cannot assign variables in other modules）
  import ..魏
  魏.king *= "：丞相-冀州牧" # 不能修改别的模块的变量（ERROR: LoadError: cannot assign variables in other modules）
  import ..吴
  吴.king *= "：车骑将军-徐州牧" # 不能修改别的模块的变量（ERROR: LoadError: cannot assign variables in other modules）
end

max_stars_repo_name: JulialangOrgCN/howtojulia

max_issues_repo_name: JulialangOrgCN/howtojulia

max_forks_repo_name: JulialangOrgCN/howtojulia


text:
"""
    prep_sims(n = 100, prep_fn = "prep.h5", K = 100.0)

Prepare `n` replicates of habitat, movement, spatial equilibium, and
catchability deviations.
"""
function prep_sims(n = 100, prep_fn = "prep.h5", K = 100.0)
    # Set seed for reproducibility. Passing RNGs directly doesn't work yet.
    Random.seed!(2020)

    # Use 100×100 gridded fishery domain for all simulations
    Ω = GriddedFisheryDomain()

    #-Habitat-------------------------------------------------------------------
    # Declare habitat distribution
    habitat_kernel = Matérn32Cov(9.0, 20.0)
    function hab_mean_fn(loc)
        hab_mean = ((-loc[1] + 50)^2 + (-loc[2] + 50)^2) / 500 - 5//2
        if hab_mean > 5
            hab_mean = 5one(hab_mean)
        end
        hab_mean
    end
    habitat_mean = hab_mean_fn.(Ω.locs)
    habitat_cov = cov(habitat_kernel, Ω)
    habitat_distribution = DomainDistribution(MvNormal(vec(habitat_mean),
                                                       habitat_cov), Ω)

    #-Movement------------------------------------------------------------------
    # Declare habitat preference function and plot realized preference
    hab_pref_fn(h) = exp(-(h + 5)^2 / 25)
    # Distance travelled in a single step decays exponentially
    # distance_fn(d) = exp(-d ^ 2 / 5)
    distance_fn(d) = 1

    #-Vessels-------------------------------------------------------------------
    # Catchability deviations - spatially correlated multiplicative noise
    catchability_devs_kern = Matérn32Cov(0.05, 30.0)
    catchability_devs_cov = cov(catchability_devs_kern, Ω)
    catchability_devs_distr = DomainDistribution(MvLogNormal,
                                                 ones(length(Ω)),
                                                 catchability_devs_cov, Ω)

    # Log-catchability deviations - rescalable option so that spatial structure
    # of catchability deviations is constant, but has different magnitudes.
    log_catchability_devs_kern = Matérn32Cov(1.0, 30.0)
    log_catchability_devs_cov = cov(log_catchability_devs_kern, Ω)
    log_catchability_devs_distr = DomainDistribution(
        MvNormal(zeros(length(Ω)),
                 log_catchability_devs_cov),
        Ω)

    h5open(prep_fn, "w") do fid
        hab_dset = create_dataset(fid,
                                  "habitat",
                                  datatype(Float64),
                                  dataspace(size(Ω)..., n),
                                  chunk = (size(Ω)..., 1))
        mov_dset = create_dataset(fid,
                                  "movement",
                                  datatype(Float64),
                                  dataspace(length(Ω), length(Ω), n),
                                  chunk = (size(Ω)..., 1))
        speq_dset = create_dataset(fid,
                                   "spatial_eq",
                                   datatype(Float64),
                                   dataspace(size(Ω)..., n),
                                   chunk = (size(Ω)..., 1))
        qdev_dset = create_dataset(fid,
                                   "catchability_devs",
                                   datatype(Float64),
                                   dataspace(size(Ω)..., n),
                                   chunk = (size(Ω)..., 1))
        log_qdev_dset = create_dataset(fid,
                                       "log_catchability_devs",
                                       datatype(Float64),
                                       dataspace(size(Ω)..., n),
                                       chunk = (size(Ω)..., 1))

        hab = zeros(size(Ω)...)
        mov = zeros(length(Ω), length(Ω))
        speq = zeros(size(Ω)...)
        qdev = zeros(size(Ω)...)
        log_qdev = zeros(size(Ω)...)

        for rlz in 1:n
            # Generate habitats and save
            hab .= rand(habitat_distribution)
            hab_dset[:, :, rlz] = hab

            # Derive movement operator and save
            mov .= MovementModel(Ω, hab, hab_pref_fn, distance_fn).M
            mov_dset[:, :, rlz] = mov

            # Find spatial equilibium distribution and save
            speq .= eqdist(MovementModel(mov, size(Ω)), K).P
            speq_dset[:, :, rlz] = speq

            # Generate spatially correlated catchability deviations
            qdev .= rand(catchability_devs_distr)
            qdev_dset[:, :, rlz] = qdev

            # Generate *log*-catchability deviations that can be rescaled
            # depending on the exact OM specification
            log_qdev .= rand(log_catchability_devs_distr)
            log_qdev_dset[:, :, rlz] = log_qdev
        end
    end

    # Return nothing; everything else accessed via saved HDF5 files
    nothing
end


text:
testOnAllBackends("Modify Array") do af
	println("\tmoddims")
	afArr = array(af, [[1, 2] [3, 4]])
	result = host(moddims(afArr, 4))

	@test result == [1, 2, 3, 4]

	afArr = array(af, [1, 2, 3, 4, 5, 6])
	result = host(moddims(afArr, 2, 3))

	@test result == [[1, 2] [3, 4] [5, 6]]

	afArr = array(af, [1, 2, 3, 4, 5, 6])
	@test_throws AFErrorException moddims(afArr, 2, 2)

	println("\tjoinArrays")
	afArr1 = array(af, [[1.0f0, 2.0f0] [4.0f0, 3.0f0]])
	afArr2 = array(af, [[5.0f0, 1.0f0] [1.0f0, 5.0f0]])

	@test host(joinArrays(0, afArr1, afArr2)) ==
		Float32[[1.0, 2.0, 5.0, 1.0] [4.0, 3.0, 1.0, 5.0]]
	@test host(joinArrays(1, afArr1, afArr2)) ==
		Float32[[1.0, 2.0] [4.0, 3.0] [5.0, 1.0] [1.0, 5.0]]

	afArr3 = array(af, [[9.0f0, 9.0f0] [9.0f0, 9.0f0]])

	@test host(joinArrays(0, afArr1, afArr2, afArr3)) ==
		Float32[[1.0, 2.0, 5.0, 1.0, 9.0, 9.0] [4.0, 3.0, 1.0, 5.0, 9.0, 9.0]]
end

max_stars_repo_name: unbornchikken/julia-ml-proto

max_issues_repo_name: unbornchikken/julia-ml-proto

max_forks_repo_name: unbornchikken/julia-ml-proto


text:
module JSON2

macro repeat(N, expr)
    blk = esc(quote end)
    foreach(x->push!(blk.args, expr), 1:N)
    return blk
end

function write{T}(io::IO, obj::T)
    Base.write(io, '{')
    fields = nfields(T)
    for i = 1:fields
        Base.write(io, '"', fieldname(T, i), "\": ")
        write(io, getfield(obj, i)) # recursively call write
        i < fields && Base.write(io, ',')
    end
    Base.write(io, '}')
    return
end

# write Associative, AbstractArray, Number, String, Nullable, Bool, Tuple
function write{T <: Associative}(io::IO, obj::T)
    Base.write(io, '{')
    len = length(obj)
    i = 1
    for k in keys(obj)
        write(io, k) # recursive
        Base.write(io, ": ")
        write(io, obj[k]) # recursive
        i < len && Base.write(io, ',')
        i += 1
    end
    Base.write(io, '}')
    return
end

function write{T <: Union{AbstractArray,Tuple}}(io::IO, obj::T)
    # always written as single array
    Base.write(io, '[')
    len = length(obj)
    for i = 1:len
        write(io, obj[i]) # recursive
        i < len && Base.write(io, ',')
    end
    Base.write(io, ']')
    return
end

write(io::IO, obj::Number) = (Base.write(io, string(obj)); return)
write(io::IO, obj::AbstractString) = (Base.write(io, '"', obj, '"'); return)
write{T}(io::IO, obj::Nullable{T}) = (isnull(obj) ? Base.write(io, "null") : write(io, get(obj)); return)
write(io::IO, obj::Void) = (Base.write(io, "null"); return)
write(io::IO, obj::Bool) = (Base.write(io, obj ? "true" : "false"); return)

@inline function readbyte(from::Base.AbstractIOBuffer, ::Type{UInt8}=UInt8)
    @inbounds byte = from.data[from.ptr]
    from.ptr = from.ptr + 1
    return byte
end

@inline function peekbyte(from::Base.AbstractIOBuffer)
    @inbounds byte = from.data[from.ptr]
    return byte
end

function read{T}(::Type{T}, io::IOBuffer)
    _ = readbyte(io) # '{'
    fields = []
    for i = 1:length(fieldnames(T))
        _ = readuntil(io, ':') # read fieldname until start of fieldvalue
        _ = readbyte(io) # read ' '
        push!(fields, read(fieldtype(T, i), io)) # recursively reads until ',' or '}'
    end
    !eof(io) && readbyte(io)
    return T(fields...)
end

function read{K,V}(::Type{Dict{K,V}}, io::IOBuffer)
    c = readbyte(io) # '{'
    dict = Dict{K,V}()
    peekbyte(io) == CLOSE_CURLY_BRACE && return dict
    while true
        key = read(K, io)
        _ = readbyte(io) # read ' '
        dict[key] = read(V, io) # recursively reads until ',' or '}'
        c = peekbyte(io)
        (c == COMMA || c == CLOSE_CURLY_BRACE || eof(io)) && (!eof(io) && readbyte(io); break)
    end
    return dict
end

const CLOSE_CURLY_BRACE = UInt8('}')
const CLOSE_SQUARE_BRACE = UInt8(']')
const COMMA = UInt8(',')

function read{T <: AbstractArray}(::Type{T}, io::IOBuffer)
    c = readbyte(io) # '['
    eT = eltype(T)
    A = eT[]
    peekbyte(io) == CLOSE_SQUARE_BRACE && return A
    while true
        push!(A, read(eT, io)) # recursively reads until ',' or ']'
        c = peekbyte(io)
        (c == COMMA || c == CLOSE_CURLY_BRACE || eof(io)) && (!eof(io) && readbyte(io); break)
    end
    return A
end

# read Associative, AbstractArray, Number, String, Nullable, Bool, Tuple
const MINUS = UInt8('-')
const PLUS = UInt8('+')
const NEG_ONE = UInt8('0') - 0x01
const TEN = UInt8('9') + 0x01
const ZERO = UInt8('0')

function read{T <: Integer}(::Type{T}, io::IOBuffer)
    v = zero(T)
    b = readbyte(io)
    negative = false
    if b == MINUS # check for leading '-' or '+'
        negative = true
        b = readbyte(io, UInt8)
    elseif b == PLUS
        b = readbyte(io, UInt8)
    end
    while NEG_ONE < b < TEN
        v *= 10
        v += b - ZERO
        eof(io) && break
        b = readbyte(io, UInt8)
    end
    return ifelse(negative, -v, v)
end

const REF = Vector{Ptr{UInt8}}(1)

function read{T <: AbstractFloat}(::Type{T}, io::IOBuffer)
    v = zero(T)
    ptr = pointer(io.data) + position(io) - 1
    v = convert(T, ccall(:jl_strtod_c, Float64, (Ptr{UInt8}, Ptr{Ptr{UInt8}}), ptr, REF))
    io.ptr += REF[1] - ptr - 1
    !eof(io) && readbyte(io)
    return v
end

const BUF = IOBuffer()

function read(::Type{String}, io::IOBuffer)
    b = readbyte(io) # '"'
    b = readbyte(io)
    while b != UInt8('"')
        Base.write(BUF, b)
        b = readbyte(io)
        if b == UInt8('\\')
            Base.write(BUF, b, readbyte(io)) # escaped double quote
            b = readbyte(io)
        end
    end
    !eof(io) && readbyte(io) # ',' or '}'
    return takebuf_string(BUF)
end

function read{T}(::Type{Nullable{T}}, io::IOBuffer)
    b = peekbyte(io)
    if b == UInt8('n')
        @repeat 4 readbyte(io)
        !eof(io) && readbyte(io)
        return Nullable{T}()
    else
        return Nullable(read(T, io))
    end
end
function read(::Type{Void}, io::IOBuffer)
    @repeat 4 readbyte(io)
    !eof(io) && readbyte(io)
    return nothing
end

function read(::Type{Bool}, io::IOBuffer)
    b = readbyte(io)
    if b == UInt8('t')
        @repeat 3 readbyte(io)
        !eof(io) && readbyte(io)
        return true
    else
        @repeat 4 readbyte(io)
        !eof(io) && readbyte(io)
        return false
    end
end

end # module

using .JSON2


text:
immutable BasePriceScenario <: Scenario end
immutable OptimalPriceScenario <: Scenario end
immutable Limit2DegreesScenario <: Scenario end
immutable SternScenario <: Scenario end
immutable SternCalibratedScenario <: Scenario end
immutable CopenhagenScenario <: Scenario end

BasePrice = BasePriceScenario()
OptimalPrice = OptimalPriceScenario()
Limit2Degrees = Limit2DegreesScenario()
Stern = SternScenario()
SternCalibrated = SternCalibratedScenario()
Copenhagen = CopenhagenScenario()

Base.show(io::IO, s::BasePriceScenario) = print(io, "Base (current policy) carbon price")
Base.show(io::IO, s::OptimalPriceScenario) = print(io, "Optimal carbon price")
Base.show(io::IO, s::Limit2DegreesScenario) = print(io, "Limit warming to 2° with damages")
Base.show(io::IO, s::SternScenario) = print(io, "Stern")
Base.show(io::IO, s::SternCalibratedScenario) = print(io, "Calibrated Stern")
Base.show(io::IO, s::CopenhagenScenario) = print(io, "Copenhagen participation")

export BasePrice, OptimalPrice, Limit2Degrees, Stern, SternCalibrated, Copenhagen


text:
using Intervals: Ending, Beginning, overlaps, contiguous, RightEndpoint, LeftEndpoint

function unique_paired_permutation(v::Vector{T}) where T
    results = Tuple{T, T}[]
    for (i, j) in unique(sort([x, y]) for x in eachindex(v), y in eachindex(v))
        push!(results, (v[i], v[j]))
    end
    return results
end

const INTERVAL_TYPES = [Interval, AnchoredInterval{Ending}, AnchoredInterval{Beginning}]

@testset "comparisons: $A vs. $B" for (A, B) in unique_paired_permutation(INTERVAL_TYPES)

    # Compare two intervals which are non-overlapping:
    # Visualization:
    #
    # [12]
    #     [45]
    @testset "non-overlapping" begin
        earlier = convert(A, Interval(1, 2, true, true))
        later = convert(B, Interval(4, 5, true, true))

        @test earlier != later
        @test !isequal(earlier, later)
        @test hash(earlier) != hash(later)

        @test isless(earlier, later)
        @test !isless(later, earlier)

        @test earlier < later
        @test !(later < earlier)

        @test earlier ≪ later
        @test !(later ≪ earlier)

        @test !issubset(earlier, later)
        @test !issubset(later, earlier)

        @test isempty(intersect(earlier, later))
        @test_throws ArgumentError merge(earlier, later)
        @test union([earlier, later]) == [earlier, later]
        @test !overlaps(earlier, later)
        @test !contiguous(earlier, later)
        @test superset([earlier, later]) == Interval(1, 5, true, true)
    end

    # Compare two intervals which "touch" but both intervals do not include that point:
    # Visualization:
    #
    # (123)
    #   (345)
    @testset "touching open/open" begin
        earlier = convert(A, Interval(1, 3, false, false))
        later = convert(B, Interval(3, 5, false, false))

        @test earlier != later
        @test !isequal(earlier, later)
        @test hash(earlier) != hash(later)

        @test isless(earlier, later)
        @test !isless(later, earlier)

        @test earlier < later
        @test !(later < earlier)

        @test earlier ≪ later
        @test !(later ≪ earlier)

        @test !issubset(earlier, later)
        @test !issubset(later, earlier)

        @test isempty(intersect(earlier, later))
        @test_throws ArgumentError merge(earlier, later)
        @test union([earlier, later]) == [earlier, later]
        @test !overlaps(earlier, later)
        @test !contiguous(earlier, later)
        @test superset([earlier, later]) == Interval(1, 5, false, false)
    end

    # Compare two intervals which "touch" and the later interval includes that point:
    # Visualization:
    #
    # (123)
    #   [345]
    @testset "touching open/closed" begin
        earlier = convert(A, Interval(1, 3, false, false))
        later = convert(B, Interval(3, 5, true, true))

        @test earlier != later
        @test !isequal(earlier, later)
        @test hash(earlier) != hash(later)

        @test isless(earlier, later)
        @test !isless(later, earlier)

        @test earlier < later
        @test !(later < earlier)

        @test earlier ≪ later
        @test !(later ≪ earlier)

        @test !issubset(earlier, later)
        @test !issubset(later, earlier)

        @test isempty(intersect(earlier, later))
        @test merge(earlier, later) == Interval(1, 5, false, true)
        @test union([earlier, later]) == [Interval(1, 5, false, true)]
        @test !overlaps(earlier, later)
        @test contiguous(earlier, later)
        @test superset([earlier, later]) == Interval(1, 5, false, true)
    end

    # Compare two intervals which "touch" and the earlier interval includes that point:
    # Visualization:
    #
    # [123]
    #   (345)
    @testset "touching closed/open" begin
        earlier = convert(A, Interval(1, 3, true, true))
        later = convert(B, Interval(3, 5, false, false))

        @test earlier != later
        @test !isequal(earlier, later)
        @test hash(earlier) != hash(later)

        @test isless(earlier, later)
        @test !isless(later, earlier)

        @test earlier < later
        @test !(later < earlier)

        @test earlier ≪ later
        @test !(later ≪ earlier)

        @test !issubset(earlier, later)
        @test !issubset(later, earlier)

        @test isempty(intersect(earlier, later))
        @test merge(earlier, later) == Interval(1, 5, true, false)
        @test union([earlier, later]) == [Interval(1, 5, true, false)]
        @test !overlaps(earlier, later)
        @test contiguous(earlier, later)
        @test superset([earlier, later]) == Interval(1, 5, true, false)
    end

    # Compare two intervals which "touch" and both intervals include that point:
    # Visualization:
    #
    # [123]
    #   [345]
    @testset "touching closed/closed" begin
        earlier = convert(A, Interval(1, 3, true, true))
        later = convert(B, Interval(3, 5, true, true))

        @test earlier != later
        @test !isequal(earlier, later)
        @test hash(earlier) != hash(later)

        @test isless(earlier, later)
        @test !isless(later, earlier)

        @test earlier < later
        @test !(later < earlier)

        @test !(earlier ≪ later)
        @test !(later ≪ earlier)

        @test !issubset(earlier, later)
        @test !issubset(later, earlier)

        @test intersect(earlier, later) == Interval(3, 3, true, true)
        @test merge(earlier, later) == Interval(1, 5, true, true)
        @test union([earlier, later]) == [Interval(1, 5, true, true)]
        @test overlaps(earlier, later)
        @test !contiguous(earlier, later)
        @test superset([earlier, later]) == Interval(1, 5, true, true)
    end

    # Compare two intervals which overlap
    # Visualization:
    #
    # [1234]
    #  [2345]
    @testset "overlapping" begin
        earlier = convert(A, Interval(1, 4, true, true))
        later = convert(B, Interval(2, 5, true, true))

        @test earlier != later
        @test !isequal(earlier, later)
        @test hash(earlier) != hash(later)

        @test isless(earlier, later)
        @test !isless(later, earlier)

        @test earlier < later
        @test !(later < earlier)

        @test !(earlier ≪ later)
        @test !(later ≪ earlier)

        @test !issubset(earlier, later)
        @test !issubset(later, earlier)

        @test intersect(earlier, later) == Interval(2, 4, true, true)
        @test merge(earlier, later) == Interval(1, 5, true, true)
        @test union([earlier, later]) == [Interval(1, 5, true, true)]
        @test overlaps(earlier, later)
        @test !contiguous(earlier, later)
        @test superset([earlier, later]) == Interval(1, 5, true, true)
    end

    @testset "equal ()/()" begin
        a = convert(A, Interval(1, 5, false, false))
        b = convert(B, Interval(1, 5, false, false))

        @test a == b
        @test isequal(a, b)
        @test hash(a) == hash(b)

        @test !isless(a, b)
        @test !isless(a, b)

        @test !(a < b)
        @test !(b < a)

        @test !(a ≪ b)
        @test !(b ≪ a)

        @test issubset(a, b)
        @test issubset(b, a)

        @test intersect(a, b) == Interval(1, 5, false, false)
        @test merge(a, b) == Interval(1, 5, false, false)
        @test union([a, b]) == [Interval(1, 5, false, false)]
        @test overlaps(a, b)
        @test !contiguous(a, b)
        @test superset([a, b]) == Interval(1, 5, false, false)
    end

    @testset "equal [)/()" begin
        a = convert(A, Interval(1, 5, true, false))
        b = convert(B, Interval(1, 5, false, false))

        @test a != b
        @test !isequal(a, b)
        @test hash(a) != hash(b)

        @test isless(a, b)
        @test !isless(b, a)

        @test a < b
        @test !(b < a)

        @test !(a ≪ b)
        @test !(b ≪ a)

        @test !issubset(a, b)
        @test issubset(b, a)

        @test intersect(a, b) == Interval(1, 5, false, false)
        @test merge(a, b) == Interval(1, 5, true, false)
        @test union([a, b]) == [Interval(1, 5, true, false)]
        @test overlaps(a, b)
        @test !contiguous(a, b)
        @test superset([a, b]) == Interval(1, 5, true, false)
    end

    @testset "equal (]/()" begin
        a = convert(A, Interval(1, 5, false, true))
        b = convert(B, Interval(1, 5, false, false))

        @test a != b
        @test !isequal(a, b)
        @test hash(a) != hash(b)

        @test !isless(a, b)
        @test !isless(b, a)

        @test !(a < b)
        @test !(b < a)

        @test !(a ≪ b)
        @test !(b ≪ a)

        @test !issubset(a, b)
        @test issubset(b, a)

        @test intersect(a, b) == Interval(1, 5, false, false)
        @test merge(a, b) == Interval(1, 5, false, true)
        @test union([a, b]) == [Interval(1, 5, false, true)]
        @test overlaps(a, b)
        @test !contiguous(a, b)
        @test superset([a, b]) == Interval(1, 5, false, true)
    end

    @testset "equal []/()" begin
        a = convert(A, Interval(1, 5, true, true))
        b = convert(B, Interval(1, 5, false, false))

        @test a != b
        @test !isequal(a, b)
        @test hash(a) != hash(b)

        @test isless(a, b)
        @test !isless(b, a)

        @test a < b
        @test !(b < a)

        @test !(a ≪ b)
        @test !(b ≪ a)

        @test !issubset(a, b)
        @test issubset(b, a)

        @test intersect(a, b) == Interval(1, 5, false, false)
        @test merge(a, b) == Interval(1, 5, true, true)
        @test union([a, b]) == [Interval(1, 5, true, true)]
        @test overlaps(a, b)
        @test !contiguous(a, b)
        @test superset([a, b]) == Interval(1, 5, true, true)
    end

    @testset "equal [)/[]" begin
        a = convert(A, Interval(1, 5, true, false))
        b = convert(B, Interval(1, 5, true, true))

        @test a != b
        @test !isequal(a, b)
        @test hash(a) != hash(b)

        @test !isless(a, b)
        @test !isless(b, a)

        @test !(a < b)
        @test !(b < a)

        @test !(a ≪ b)
        @test !(b ≪ a)

        @test issubset(a, b)
        @test !issubset(b, a)

        @test intersect(a, b) == Interval(1, 5, true, false)
        @test merge(a, b) == Interval(1, 5, true, true)
        @test union([a, b]) == [Interval(1, 5, true, true)]
        @test overlaps(a, b)
        @test !contiguous(a, b)
        @test superset([a, b]) == Interval(1, 5, true, true)
    end

    @testset "equal (]/[]" begin
        a = convert(A, Interval(1, 5, false, true))
        b = convert(B, Interval(1, 5, true, true))

        @test a != b
        @test !isequal(a, b)
        @test hash(a) != hash(b)

        @test !isless(a, b)
        @test isless(b, a)

        @test !(a < b)
        @test b < a

        @test !(a ≪ b)
        @test !(b ≪ a)

        @test issubset(a, b)
        @test !issubset(b, a)

        @test intersect(a, b) == Interval(1, 5, false, true)
        @test merge(a, b) == Interval(1, 5, true, true)
        @test union([a, b]) == [Interval(1, 5, true, true)]
        @test overlaps(a, b)
        @test !contiguous(a, b)
        @test superset([a, b]) == Interval(1, 5, true, true)
    end

    @testset "equal []/[]" begin
        a = convert(A, Interval(1, 5, true, true))
        b = convert(B, Interval(1, 5, true, true))

        @test a == b
        @test isequal(a, b)
        @test hash(a) == hash(b)

        @test !isless(a, b)
        @test !isless(b, a)

        @test !(a < b)
        @test !(b < a)

        @test !(a ≪ b)
        @test !(b ≪ a)

        @test issubset(a, b)
        @test issubset(b, a)

        @test intersect(a, b) == Interval(1, 5, true, true)
        @test merge(a, b) == Interval(1, 5, true, true)
        @test union([a, b]) == [Interval(1, 5, true, true)]
        @test overlaps(a, b)
        @test !contiguous(a, b)
        @test superset([a, b]) == Interval(1, 5, true, true)
    end

    @testset "equal -0.0/0.0" begin
        # Skip tests when we're comparing ending and beginning anchored intervals
        if Set((A, B)) != Set((AnchoredInterval{Ending}, AnchoredInterval{Beginning}))
            a = convert(A, Interval(0.0, -0.0))
            b = convert(B, Interval(-0.0, 0.0))

            @test a == b
            @test !isequal(a, b)
            @test hash(a) != hash(b)

            # All other comparison should still work as expected
            @test !isless(a, b)
            @test !isless(b, a)

            @test !(a < b)
            @test !(b < a)

            @test !(a ≪ b)
            @test !(b ≪ a)

            @test issubset(a, b)
            @test issubset(b, a)

            @test intersect(a, b) == Interval(0.0, 0.0)
            @test merge(a, b) == Interval(0.0, 0.0)
            @test union([a, b]) == [Interval(0.0, 0.0)]
            @test overlaps(a, b)
            @test !contiguous(a, b)
            @test superset([a, b]) == Interval(0.0, 0.0)
        end
    end
    # Compare two intervals where the first interval is contained by the second
    # Visualization:
    #
    #  [234]
    # [12345]
    @testset "containing" begin
        smaller = convert(A, Interval(2, 4, true, true))
        larger = convert(B, Interval(1, 5, true, true))

        @test smaller != larger
        @test !isequal(smaller, larger)
        @test hash(smaller) != hash(larger)

        @test !isless(smaller, larger)
        @test isless(larger, smaller)

        @test !(smaller < larger)
        @test larger < smaller

        @test !(smaller ≪ larger)
        @test !(larger ≪ smaller)

        @test issubset(smaller, larger)
        @test !issubset(larger, smaller)

        @test intersect(smaller, larger) == Interval(smaller)
        @test merge(smaller, larger) == Interval(larger)
        @test union([smaller, larger]) == [Interval(larger)]
        @test overlaps(smaller, larger)
        @test !contiguous(smaller, larger)
        @test superset([smaller, larger]) == Interval(1, 5, true, true)
    end
end


text:
"""
    InheritableFields

Define abstract types with fields to be inherited by concrete subtypes.
"""
module InheritableFields
export @inheritable, @inheriting, validate_args
#export FieldDecl, map_symbols, type_decls, type_field_decls

# This seems to really work!!
# TODO: Tidy up.  Maybe move some stuff to TypeTools.
# TODO: Vet more thoroughly
# TODO: Handle Vararg parametric types
# TODO: Because type declarations and field declarations are stored as expressions,
#       namespaces are not utilized.  Thmis means same-named types in different
#       namespaces are not disambiguated.  Also, if an @inheriting type inherits an
#       @inheritable type definied in a different namespace, the inherited fields may
#       involve type names that are not known in the inheriting namespace.
#
#       Possible approaches:
#           - Qualify all names in type declarations by the module in which the
#               declaration was made, e.g. using @__MODULE__.  The challenge here is
#               knowing which parts of an expression need to be qualified. Perhaps
#               all symbols that are not typevars?
#           - Store declarations using evaluated types rather than expressions.
#               While this will work for type names alone, the challenge is what to
#               do with type parameters: They may need to be evaluated as well, but
#               may involve type parameters that aren't in the namespace.
#           - Create a dummy datatype with the fields.  Then translated field types can
#               can be obtained by looking them up with a fully parameterized dummy
#               datatype.  But we must make sure the type parameters are not constrained
#               since we might want to fill them with symbols or other type parameters.
#               Also, this will yield an actual type, not an expression ...
#
#          The first approach is in progress. So far, so good.
#          TODO: Move name qualification from @inheriting to process_typedef?
#                Maybe not, because then it would hhappen for @inheriting also ...
#          TODO: Qualify supertype name also.  But this makes it hard to use as a key.
#                Maybe use actual types for keys, but store parameter expressions
#                   separately.
#
# TODO: "Store" the type declarations in functions, which are global and can be precompiled.
#       This would also make it easier to look up types in namespaces, since we could
#       dispatch on the actual type instead of its name.  But then we should store
#       the formal parameter expressions separately from the types.
# TODO: Allow deriving from intermediary non-@inheritable types.  This will require extracting
#       the formal parameters from the type definition and mapping them, either directly or by
#       turning them into expressions first.

# Here's an example of the namespace issue.
# module MyModule
# using InheritableFields
# export A
#
# 	struct S{T}
# 		x::Vector{T}
# 	end
#
#
# 	@inheritable A{T} begin
# 			s::S{T}
# 		end
# end
#
# (in Main)
# using InheritableFields
# using Main.MyModule
# @inheriting struct B{X} <: A{X} end
#
# Since S is not exported to A, the field declaration s::S{T} from will not work in B.
# Thus s::S{T} needs to become s::MyModule.S{T}, which in B becomes s::MyModule.S{X}.
# Note that MyModule is necessarily a sufficient qualifier, since if MyModule were not
# not visible then we (probably) could not have referenced A; also, MyModule will encompass
# anything that was visible in the definition of A.

using MacroTools
using MacroTools: postwalk, prewalk
using TypeTools
using OrderedCollections

import TypeTools.map_symbols

# The declaration of each inheritable type are stored in a global registry.
# The declaration consists of:
#   - The type's name and formal parameters
#   - Its supertype's name and formal parameters
#   - The field names, their types, and optional default values
# All these are stored as expressions. When a concrete subtype is defined, these
# declarations are retrieved, translated into the formal parameters of the concrete type,
# and incorporated into the concrete type's definition.

# Types for Field declarations and type declarations
const Expression = Any
const FieldDecl = NamedTuple{(:name, :type, :default), Tuple{Symbol, Expression, Any}}
# (type_signature, supertype_signature, field_declarations)
const TypeDecl = Tuple{Expression, Expression, OrderedDict{Symbol, FieldDecl}}

# The global "registry" is a function that returns the type delcaration (::TypeDecl) of an
# @inheritable type (or returns nothing).
# TODO:  Currently accepts a symbol?  Change to accepting a type?
type_declaration(::Val{<:Any}) = nothing

# Argument validator for @inheritable types
function validate_args end

# This stores the signatures of the declared types and their supertypes
#const type_decls = Dict{Symbol, Tuple{Expression, Expression}}()
# This stores the expressions of fields declared for abtract types
#const type_field_decls = Dict{Symbol, OrderedDict{Symbol, FieldDecl}}()

"""
    @inheritable ‹type_decl› begin [fields] [validator] end

Define an abstract type with associated fields that are incorporated into concrete subtypes.

Each field declaration has the form `name[::Type] [ = defaultvalue]`.

The type declaration may also include a validator function to ensure that concrete
subtypes are constructed with valid field values. The validator must be named `validate_args`
and must have the same parameterization and signature that a default constructor would
have. The validator should either return valid arguments for a default constructor or
throw an exception.

# Example
```
@inheritable A{T<:Number}
begin
    x::T = zero(T)
    y
    function validate_args(x, y)
        x < zero(T) || error("x must be non-negative")
        return (x,y)
    end
end
```
See also:  [`@inherit`](@ref)
"""
macro inheritable(type_decl, body = :(begin end) )
    (type_sig, type_name, type_params, type_qualparams, unbound_sig, super_sig, field_decls, validators) = process_typedef(type_decl, body)

    caller_mod = __module__
    #@info "Defining inheritable type $type_sig <: $super_sig in module $caller_mod"

    # create a default "validator" if none was provided
    if isempty(validators)
        field_names = keys(field_decls)
        push!(validators, :( InheritableFields.validate_args(::Type{$unbound_sig}, $(field_names...)) where {$(type_qualparams...)} = ($(field_names...),) ) )
    end

    caller_name = nameof(caller_mod)
    for i in eachindex(field_decls)
        fdecl = field_decls[i]
        #print("Qualifying $(fdecl.type) as ")
        new_type = qualify_symbols(fdecl.type, type_params, caller_name)
        new_default = qualify_symbols(fdecl.default, type_params, caller_name)
        fdecl = (name = fdecl.name, type = new_type, default = new_default)
        #println(fdecl.type)
        field_decls[i] = fdecl
    end
    newtype_decl = TypeDecl((unbound_sig, super_sig, field_decls))

    expr = quote
#                try
                   Base.@__doc__ abstract type $type_sig <: $super_sig end
                   $(validators...)
                   InheritableFields.type_declaration(::Val{$(QuoteNode(type_name))}) = $newtype_decl
#            catch e
#                delete!(InheritableFields.type_declarations, $(QuoteNode(type_name)));
#                rethrow(e)
#            end
        end
#    println( MacroTools.prewalk(rmlines, esc(expr)))
    return esc(expr)
#    return MacroTools.prewalk(rmlines, esc(expr))
end

"""
    @inheriting [mutable] struct ‹type_decl› [fields] [validator] end

Define a concrete type that inherits fields from supertypes declared with `@inheritable`.
The fields of all `inheritable` supertypes are automatically incorporated into the
definition of the concrete type, in order of increasingly specialized supertypes.
# EXample
```
@inheritable A{T}
begin
    x::T = zero(T)
    y
end

@inheriting struct B{S} <: A{S}
    z::String = "hello"
end
```
Then `B` has fields `x::S, y::Any, z::String`. (Note that the type parameters of `B` are
propagated to `A`.)  An instane of `B` can be created by the default constructor,
`B{Float64}(1.2, -5, "bye")` are one of several convenience constructors that are
automatically created:
```
# Construct with keyword arguments
B(; x::S = zero(S), y, z::String = "hello") where {S} = B{S}(x, y, z)
B{S}(; x::S = zero(S), y::Any, z::String = "hello") where {S} = B{S}(x, y, z)

# Construct from another instance, modifying selected fields with keyword arguments
B(obj::B; x::S = obj.x, y::Any = obj.y, z::String = obj.z) where {S} = B{S}(x, y, z)
B{S}(obj::B{S}; x::S = obj.x, y::Any = obj.y, z::String = obj.z) where {S} = B{S}(x, y, z)

```
(The second member of each pair is not created if B has no type parameters.)

See also: [`@inheritable`](@ref)
"""
macro inheriting(typedef)
    return esc(inheriting(typedef))
end

# Function version. More convenient for calling from other macros
function inheriting(typedef)
    # parse the signature
    typedef.head == :struct || error("@inherit must be followed by a structure definition")
    ismutable = typedef.args[1]

    type_decl = typedef.args[2]
    body = typedef.args[3]
    inheriting(type_decl, body, ismutable = ismutable)
end

function inheriting(type_decl, body; ismutable)
    (type_sig, type_name, type_params, type_qualparams, unbound_sig, super_sig, field_decls, validators) = process_typedef(type_decl, body)

    # @info "Defining inherited type $type_sig <: $super_sig"

    newtype_decl =  TypeDecl((unbound_sig, super_sig, field_decls))

    # println("Adding declaration: ", type_declarations[type_name][1], " <: ", type_declarations[type_name][2])

    # Assemble the field declarations for this type and all ancestor types.
    # The search will proceed up the type hierarchy, but we will eventually reverse the
    # order so that fields are listed in the order defined from ancestor down to concerete type.

    struct_field_decls = Expression[]
    kw_args1 = Expression[]
    kw_args2 = Expression[]
    constr_args = Expression[]

    ancestor_name = type_name
    ancestor_params = type_params
    ancestor_unbound_sig = unbound_sig
    formal_sig = type_sig
    next_sig = super_sig
    formal_params::Vector{Symbol} = type_params

    while ancestor_name != :Any
        # @info "  Retrieving fields of $ancestor_name{$(ancestor_params...)}"

        if ancestor_name == type_name || type_declaration(Val(ancestor_name)) != nothing
            # (formal_sig, next_sig) = type_decls[ancestor_name]
            # field_decls = type_field_decls[ancestor_name]
            if ancestor_name != type_name
                (formal_sig, next_sig, field_decls) = type_declaration(Val(ancestor_name))
                (_, formal_params, _) = parse_typesig(formal_sig)
            end
            # println("processing ", ancestor_name)
            # println("  ancestor_params = ", ancestor_params)
            # println("  ancestor_unbound_sig = ", ancestor_unbound_sig)
            # println("  formal_sig = ", formal_sig)
            # println("  formal_params = ", formal_params)
            # println("  next_sig = ", next_sig)
            _struct_field_decls = Expression[]
            _kw_args1 = Expression[]
            _kw_args2 = Expression[]
            if length(ancestor_params) != length(formal_params)
                @info "type = $ancestor_name"
                @info "ancestor_params = $ancestor_params"
                @info "formal_params = $formal_params"
                error("The declaration of $ancestor_name or one of its subtypes did not specify all required parameters")
            end
            # println("Processing type $ancestor_name with parameters {$(ancestor_params...)}, formal parameters {$(formal_params...)}")
            for fdecl in values(field_decls)
                # println("  Adding field ", fdecl.name)
                # translate the field declaration to the ancestor's parameters
                # print("inheriting field $fdecl as ")
                fdecl = map_symbols(fdecl, formal_params, ancestor_params)
                # @info "   Inheriting field $fdecl"
                # add the declaration w/o the default value to the struct's declared fields
                push!(_struct_field_decls, plain_field_decl(fdecl))
                # add the full declaration to the list of arguments for the keyword validator
                push!(_kw_args1, kw_field_decl(fdecl))
                push!(_kw_args2, kw_field_decl_obj(fdecl))
            end
            prepend!(struct_field_decls, _struct_field_decls)
            prepend!(kw_args1, _kw_args1)
            prepend!(kw_args2, _kw_args2)
            pushfirst!(constr_args, :( InheritableFields.validate_args($ancestor_unbound_sig, $(keys(field_decls)...) )... ) )
            # When we handle non-@inheritable ancestors, this should go outside the if-else-end
            next_sig = map_symbols(next_sig, formal_params, ancestor_params)
            (ancestor_name, ancestor_params, _) = parse_typesig(next_sig)
            if isempty(ancestor_params)
                ancestor_unbound_sig = ancestor_name
            else
                ancestor_unbound_sig = :( $(ancestor_name){$(ancestor_params...)} )
            end
        else
            @warn "In defining $type_name, $ancestor_name is not an `@inheritable` type. No more ancestors will be `@inherit`ed."
            break
        end
    end

    # Define the keyword constructors
    kwconstrs = Expr[]

    # keywords with inferred parameterization
    push!(kwconstrs, :( $type_name(; $(kw_args1...)) where {$(type_qualparams...)} = $unbound_sig($(constr_args...)) ) )

    # Copy-with-modifications constructor
    push!(kwconstrs, :( $type_name(obj::$type_name; $(kw_args2...)) where {$(type_qualparams...)} = $unbound_sig($(constr_args...)) ))

    # Same thing, but with explicit type parameters
    if ~isempty(type_params)
        push!(kwconstrs, :( $unbound_sig(; $(kw_args1...)) where {$(type_qualparams...)} = $unbound_sig($(constr_args...)) ) )
        push!(kwconstrs, :( $unbound_sig(obj::$unbound_sig; $(kw_args2...)) where {$(type_qualparams...)} = $unbound_sig($(constr_args...)) ))
    end
    struct_def = Expr(:struct, ismutable, :( $type_sig <: $super_sig ), Expr(:block, struct_field_decls...))

    expr =  quote
                Base.@__doc__ $struct_def
                $(validators...)
                $(kwconstrs...)
                copy(obj::$type_name) = $type_name(obj)
                InheritableFields.type_declaration(::Val{$(QuoteNode(type_name))}) = $newtype_decl
            end
    # println(expr)
    return expr
    # return MacroTools.prewalk(rmlines, esc(expr))
end

# Process the components of a type definition, connsisting of a "declaration" and a "body".
# The "declaration" is the name of the type, its parameterization, and its supertype,
# e.g.  A{T<:Number} <: B{T}.
#   A{T<:Number} is the "signature"
#   A{T} is the "unbound signature" -- needed for method arguments
#   {T <: Number} is the parameterization -- needed for "where" clauses
#   T is the "type var".
# The "body" are all the lines after the type declaration.
#   In the body we allow (1) field declarations with optional types and optional default
#   values, and (2) functions that have the same signature as the default constructor.
function process_typedef(type_decl::Expression, body::Expression)
    # Parse the declaration
    (type_sig, super_sig) = parse_typedecl(type_decl)
    (type_name, type_params, type_qualparams) = parse_typesig(type_sig)

    # Construct a version of the type signature without only unbound parameters (for
    # function signatures)
    if isempty(type_params)
        unbound_sig = type_sig
    else
        unbound_sig = :( $(type_name){$(type_params...)} )
    end

    # Parse the body
    field_decls = OrderedDict{Symbol, FieldDecl}()
    validators = Expression[]

    # Evidently @capture ignores LineNumberNodes, which is why it is useful
    @capture(body, begin body_decls__ end) || error("Body must be a block.")
    # loop over lines of the body
    for decl in body_decls
        # println("processing body declaration ", decl)
        isfunction = @capture(decl, ((func_(args__) | func_(args__) where params_) = body_ ) | ( function (func_(args__) | func_(args__) where params_) body_ end ))

        if isfunction
            # Check whether we have a well-formed validator
            (func == :validate_args) || error("The only function that may be defined in an @inheritable type must be named 'validate_args'.")
            (params == nothing) || @warn "Ignoring the `where {...}` clause of the validator; the necessary `where` cluase is automatically derived from the type declaration."

            # We appear to have a validator.  Make sure it's the only one
            length(validators) > 0 && error("Type declaration can have at most one validator")

            # Modify the validator:  Qualify the name and add the type as the first argument
            decl = postwalk(decl) do ex
                    if (ex isa Expr) && (ex.head == :call) && (ex.args[1] == :validate_args)
                        ex.args = [:(InheritableFields.validate_args); :(::Type{$unbound_sig}); ex.args[2:end]]
                    end
                    return ex
                end

            # Add a "where" clause with the type's parameters
             decl.args[1] = Expr(:where, decl.args[1], type_params...)
            push!(validators, decl)
        elseif @capture(decl, ((field_name_::field_type_  | field_name_) = def_val_) | (field_name_::field_type_ | field_name_))
            (field_type === nothing) && (field_type = :Any)
            field_decls[field_name] = FieldDecl((field_name, field_type, def_val))
        else
            error("In definition of type $type_name, could not parse declaration $decl")
        end
    end

    # create a default "validator" if none was provided
    if isempty(validators)
        field_names = keys(field_decls)
        push!(validators, :( InheritableFields.validate_args(::Type{$unbound_sig}, $(field_names...)) where {$(type_qualparams...)} = ($(field_names...),) ) )
    end

    return (type_sig, type_name, type_params, type_qualparams, unbound_sig, super_sig, field_decls, validators)
end

map_symbols(fd::FieldDecl, from_syms, to_syms) = FieldDecl(map(ex->map_symbols(ex, from_syms, to_syms), fd))

# Return the expression for a keyword-type of field declaration
function kw_field_decl(fdecl::FieldDecl)
    ex = Expr(:(::), fdecl.name, fdecl.type)
    if fdecl.default != nothing
        ex = Expr(:kw, ex, fdecl.default)
    end
    return ex
end

function kw_field_decl_obj(fdecl::FieldDecl)
    ex = Expr(:(::), fdecl.name, fdecl.type)
    ex = Expr(:kw, ex, :( obj.$(fdecl.name) ))
    return ex
end

# Return the expression for a field declaration, omitting the default value
plain_field_decl(fdecl::FieldDecl) = Expr(:(::), fdecl.name, fdecl.type)

# Qualify symbols in an expression with namespace
function qualify_symbols(expr, exclude_syms, namespace)
    qexpr = postwalk(expr) do ex
            if (ex isa Symbol) && !(ex in exclude_syms)
                ex =  :( $namespace.$ex )
            end
            return ex
        end
end

end

# -----------------------------------------------------------
#   OBSOLETE STUFF
#

# Name of the associated data structure
# dataname = Symbol("$(typename)Data")
# if isempty(typeparams)
#     datasig = :( $(dataname) )
# else
#     datasig = :( $(dataname){$(typeparams...)} )
# end

#     # Functions that store fields' default values
#     default_funs = Expression[]
#     for (field_name, val) in defaults
#         # We need defaultvalue_expr to return an expression with input-dependent parameters.
#         #println("val = $val")
#         for typevar in typevars
#             val = MacroTools.postwalk(item -> (item == typevar) ? Expr(:$, typevar) : item, val)
#         end
#         val = Expr(:quote, val)
#         #println("val = $val")
#         push!(default_funs, MacroTools.prewalk(rmlines, quote
# #            InheritableFields.hasdefault(::Type{$unboundsig}, ::Val{$(QuoteNode(field_name))}) where {$(typeparams...)} = true
#             InheritableFields.defaultvalue_expr(::Val{$(QuoteNode(field_name))}, ::Val{$(QuoteNode(typename))}, $(typevars...)) = $val
#         end
#         ))
#         #show(default_funs[end])
#     end
#
#     # Create a function that maps a typename and formal parameters to it's supertype's name
#     # and formal parameters
#     (supername, superparams) = parse_typeexpr(supersig)
#     superparam_exprs = superparams
#     println("superparams_exprs = ", superparam_exprs)
#     # dump(superparams_expr)
#     for i in eachindex(superparam_exprs)
#         for typevar in typevars
#             if superparam_exprs[i] == typevar
#                 superparam_exprs[i] = Expr(:quote, Expr(:$, typevar))
#             end
#         end
#     end
#     supertype_fun = :( InheritableFields.supertype_expr(::Val{$(QuoteNode(typename))}, ($(typevars...),)) = ($(QuoteNode(supername)), ($(superparam_exprs...),) ) )
#

# Create the code to be evaluated
# - Declare the abstract type
# - Define the validators
# - Record the new type in the table of inheritable types
# - Record its field declarations
# We do these last two steps in the evaluated expression rather than within this macro,
# in case something fails. and their supertypes
# -
# quot_type_name = QuoteNode(type_name)
# quot_unbound_sig = QuoteNode(unbound_sig)
# quot_super_sig = QuoteNode(super_sig)


text:
using SignatureGB
using Test
using Singular

SG = SignatureGB

include("./tests.jl")


text:
"""
Power nonlinearity, with energy C ∫ρ^α where ρ is the density
"""
struct PowerNonlinearity
    C::Real
    α::Real
end
(P::PowerNonlinearity)(::AbstractBasis{T}) where {T} = TermPowerNonlinearity{T}(P.C, P.α)

struct TermPowerNonlinearity{T <: Real}<: TermNonlinear
    C::T
    α::T
end

function ene_ops(term::TermPowerNonlinearity, basis::PlaneWaveBasis, ψ, occ; ρ, kwargs...)
    E = term.C * sum(ρ .^ term.α) * basis.dvol
    potential = @. term.C * term.α * ρ^(term.α-1)

    # In the case of collinear spin, the potential is spin-dependent
    ops = [RealSpaceMultiplication(basis, kpt, potential[:, :, :, kpt.spin])
           for kpt in basis.kpoints]
    (E=E, ops=ops)
end

_pnl_kernel(C, α, ρ) = @. C * α * (α-1) * ρ^(α-2)

function compute_kernel(term::TermPowerNonlinearity, ::AbstractBasis; ρ, kwargs...)
    Diagonal(vec(_pnl_kernel(term.C, term.α, ρ)))
end

function apply_kernel(term::TermPowerNonlinearity, ::AbstractBasis, δρ; ρ, kwargs...)
    _pnl_kernel(term.C, term.α, ρ) .* δρ
end


text:
using .FormalPowerSeries

@show cosine = FormalPowerSeries.CosineFPS()
@show sine = FormalPowerSeries.SineFPS()

intcosine = FormalPowerSeries.integrate(cosine)
intsine = FormalPowerSeries.integrate(sine)
uminintsine = 1 - FormalPowerSeries.integrate(sine)

# Check coefficients up to the 20th term
coefsine = collect(Iterators.take(sine, 20))
coefintcosine = collect(Iterators.take(intcosine, 20))

coefcosine = collect(Iterators.take(cosine, 20))
coefuminintsine = collect(Iterators.take(uminintsine, 20))

@assert coefsine == coefintcosine "The integral of cos should be sin"
@assert coefcosine == coefuminintsine "1 minus the integral of sin should be cos"

max_stars_repo_name: ethansaxenian/RosettaDecode

max_issues_repo_name: ethansaxenian/RosettaDecode

max_forks_repo_name: ethansaxenian/RosettaDecode