Skip to content

Commit 75c2e72

Browse files
ajkeller34StefanKarpinski
authored andcommitted
Lower x^n (literal n) to Base.literal_pow(^, x, Val{n}) (#20889)
Fixes #20882
1 parent e91065c commit 75c2e72

File tree

5 files changed

+31
-21
lines changed

5 files changed

+31
-21
lines changed

NEWS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ Language changes
7474
`Vector{T} = Array{T,1}` or a `const` assignment.
7575
7676
* Experimental feature: `x^n` for integer literals `n` (e.g. `x^3`
77-
or `x^-3`) is now lowered to `x^Val{n}`, to enable compile-time
78-
specialization for literal integer exponents ([#20530]).
77+
or `x^-3`) is now lowered to `Base.literal_pow(^, x, Val{n})`, to enable
78+
compile-time specialization for literal integer exponents ([#20530], [#20889]).
7979
8080
Breaking changes
8181
----------------

base/intfuncs.jl

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -195,29 +195,28 @@ end
195195
^(x::Number, p::Integer) = power_by_squaring(x,p)
196196
^(x, p::Integer) = power_by_squaring(x,p)
197197

198-
# x^p for any literal integer p is lowered to x^Val{p},
198+
# x^p for any literal integer p is lowered to Base.literal_pow(^, x, Val{p})
199199
# to enable compile-time optimizations specialized to p.
200-
# However, we still need a fallback that calls the general ^.
201-
# To avoid ambiguities for methods that dispatch on the
202-
# first argument, we dispatch the fallback via internal_pow.
200+
# However, we still need a fallback that calls the function ^ which may either
201+
# mean Base.^ or something else, depending on context.
203202
# We mark these @inline since if the target is marked @inline,
204203
# we want to make sure that gets propagated,
205204
# even if it is over the inlining threshold.
206-
@inline ^(x, p) = internal_pow(x, p)
207-
@inline internal_pow{p}(x, ::Type{Val{p}}) = x^p
205+
@inline literal_pow{p}(f, x, ::Type{Val{p}}) = f(x,p)
208206

209207
# Restrict inlining to hardware-supported arithmetic types, which
210-
# are fast enough to benefit from inlining. This also makes it
211-
# easier to override ^ without having to override the Val method.
208+
# are fast enough to benefit from inlining.
212209
const HWReal = Union{Int8,Int16,Int32,Int64,UInt8,UInt16,UInt32,UInt64,Float32,Float64}
213210
const HWNumber = Union{HWReal, Complex{<:HWReal}, Rational{<:HWReal}}
214211

215212
# inference.jl has complicated logic to inline x^2 and x^3 for
216-
# numeric types. In terms of Val we can do it much more simply:
217-
@inline internal_pow(x::HWNumber, ::Type{Val{0}}) = one(x)
218-
@inline internal_pow(x::HWNumber, ::Type{Val{1}}) = x
219-
@inline internal_pow(x::HWNumber, ::Type{Val{2}}) = x*x
220-
@inline internal_pow(x::HWNumber, ::Type{Val{3}}) = x*x*x
213+
# numeric types. In terms of Val we can do it much more simply.
214+
# (The first argument prevents unexpected behavior if a function ^
215+
# is defined that is not equal to Base.^)
216+
@inline literal_pow(::typeof(^), x::HWNumber, ::Type{Val{0}}) = one(x)
217+
@inline literal_pow(::typeof(^), x::HWNumber, ::Type{Val{1}}) = x
218+
@inline literal_pow(::typeof(^), x::HWNumber, ::Type{Val{2}}) = x*x
219+
@inline literal_pow(::typeof(^), x::HWNumber, ::Type{Val{3}}) = x*x*x
221220

222221
# b^p mod m
223222

base/promotion.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,11 @@ end
254254
Exponentiation operator. If `x` is a matrix, computes matrix exponentiation.
255255
256256
If `y` is an `Int` literal (e.g. `2` in `x^2` or `-3` in `x^-3`), the Julia code
257-
`x^y` is transformed by the compiler to `x^Val{y}`, to enable compile-time
258-
specialization on the value of the exponent. (As a default fallback,
259-
however, `x^Val{y}` simply calls the `^(x,y)` function.)
257+
`x^y` is transformed by the compiler to `Base.literal_pow(^, x, Val{y})`, to
258+
enable compile-time specialization on the value of the exponent.
259+
(As a default fallback we have `Base.literal_pow(^, x, Val{y}) = ^(x,y)`,
260+
where usually `^ == Base.^` unless `^` has been defined in the calling
261+
namespace.)
260262
261263
```jldoctest
262264
julia> 3^5

src/julia-syntax.scm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2057,7 +2057,7 @@
20572057

20582058
((and (eq? f '^) (length= e 4) (integer? (cadddr e)))
20592059
(expand-forms
2060-
`(call ^ ,(caddr e) (call (core apply_type) (top Val) ,(cadddr e)))))
2060+
`(call (top literal_pow) ^ ,(caddr e) (call (core apply_type) (top Val) ,(cadddr e)))))
20612061

20622062
((and (eq? f '*) (length= e 4))
20632063
(expand-transposed-op

test/numbers.jl

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2903,9 +2903,12 @@ end
29032903
end
29042904

29052905
import Base.^
2906-
immutable PR20530; end
2906+
struct PR20530; end
2907+
struct PR20889; x; end
29072908
^(::PR20530, p::Int) = 1
2908-
^{p}(::PR20530, ::Type{Val{p}}) = 2
2909+
^(t::PR20889, b) = t.x + b
2910+
^(t::PR20889, b::Integer) = t.x + b
2911+
Base.literal_pow{p}(::typeof(^), ::PR20530, ::Type{Val{p}}) = 2
29092912
@testset "literal powers" begin
29102913
x = PR20530()
29112914
p = 2
@@ -2923,6 +2926,12 @@ immutable PR20530; end
29232926
end
29242927
end
29252928
end
2929+
@test PR20889(2)^3 == 5
2930+
end
2931+
module M20889 # do we get the expected behavior without importing Base.^?
2932+
struct PR20889; x; end
2933+
^(t::PR20889, b) = t.x + b
2934+
Base.Test.@test PR20889(2)^3 == 5
29262935
end
29272936

29282937
@testset "iszero" begin

0 commit comments

Comments
 (0)