Skip to content

Base.rest() (via splat-destructuring) has bad effects #50046

Open
@staticfloat

Description

If a user writes code such as:

function resting_sum((_, x, y...),)
    return x, +(x, y...)
end

The y... in the argument destructuring is lowered via a Base.rest(); this is inferred with terrible effects, as shown in the following example:

using Cthulhu

@noinline function resting_sum((_, x, y...),)
    return x, +(x, y...)
end

function foo(x, ys)
    return resting_sum((nothing, x, ys...),)
end


N = 12
x = 1
ys = ntuple(idx -> 1, N-1)
@assert foo(x, ys) == (1, N)
@descend foo(x, ys)

Which results in:

%13 = invoke resting_sum(::Tuple{Nothing, Vararg{Int64, 12}})::Tuple{Int64, Int64} (!c,!e,!n,!t,!s,!m,+i)

Note the difference if we apply a simple change to avoid the destructuring and instead use Base.tail() to pull out the last elements:

@noinline function tailing_sum(xs)
    return xs[2], +(Base.tail(xs)...)
end
function bar(x, ys)
    return tailing_sum((nothing, x, ys...),)
end
@assert bar(x, ys) == (1, N)
@descend bar(x, ys)

Which results in:

%13 = invoke tailing_sum(::Tuple{Nothing, Vararg{Int64, 12}})::Tuple{Int64, Int64} (+c,+e,+n,+t,+s,+m,+i)

We should improve the inferrability/effects of Base.rest() to allow users to use this convenient syntax.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions