Julia: _apply inlining optimization discards expressions

Created on 13 Jun 2017  路  6Comments  路  Source: JuliaLang/julia

Edit: See a few posts down for a simpler reproduction of the problem that does not involve Unitful.

Sorry for the lack of a precise title, but I'm not sure what the root of the problem is here:

julia> using Unitful
INFO: Recompiling stale cache file /Users/ajkeller/.julia/lib/v0.6/Unitful.ji for module Unitful.

julia> Pkg.status("Unitful")
 - Unitful                       0.2.4

julia> dimension(u"H")  # this is incorrect
饾悎^-2

This is not the dimension of a henry, however the type is correct:

julia> typeof(dimension(u"H")) # this is correct
Unitful.Dimensions{(Unitful.Dimension{:Current}(-2//1), Unitful.Dimension{:Length}(2//1), Unitful.Dimension{:Mass}(1//1), Unitful.Dimension{:Time}(-2//1))}

julia> ans() # making an object from the correct type is still shown incorrectly
饾悎^-2

It seems like some issue with how the dimensions are shown? I would ordinarily suspect that it's Unitful's fault, but this problem doesn't happen with Julia 0.5.2 and the display code is the same. This problem doesn't happen with all units / dimensions either:

julia> dimension(u"J") # this is correct
饾悑^2 饾悓 饾悡^-2

julia> typeof(dimension(u"J")) # this is correct
Unitful.Dimensions{(Unitful.Dimension{:Length}(2//1), Unitful.Dimension{:Mass}(1//1), Unitful.Dimension{:Time}(-2//1))}

I'll see if this problem happens with other 0.6 RCs.

bug regression

Most helpful comment

Also, very very minor point: for side effects, use foreach instead of map.

All 6 comments

Definitely something strange going on here. Semi-reduced code on RC2:

julia> function f(io::IO, x)
           tup = typeof(x).parameters[1]
           map(tup) do y
               print(io, " ")
               show(io,y)
           end
           nothing
       end
f (generic function with 1 method)

julia> f(STDOUT, dimension(u"H"))
 Unitful.Dimension{:Current}(-2//1)
julia> f(STDOUT, dimension(u"J"))
 Unitful.Dimension{:Length}(2//1) Unitful.Dimension{:Mass}(1//1) Unitful.Dimension{:Time}(-2//1)

All further reductions I tried no longer reproduced the bug.

Here's a further reduction that you can do without loading Unitful:

  | | |_| | | | (_| |  |  Version 0.6.0-rc3.0 (2017-06-07 11:53 UTC)
 _/ |\__'_|_|_|\__'_|  |  Official http://julialang.org/ release
|__/                   |  x86_64-apple-darwin13.4.0

julia> struct X{T} end

julia> struct Y{T}
         x::Rational{Int}
       end

julia> function f(io::IO, x)
                  tup = typeof(x).parameters[1]
                  map(tup) do y
                      print(io, " ")
                      show(io,y)
                  end
                  nothing
              end
f (generic function with 1 method)

julia> f(STDOUT, X{(Y{:Current}(-2//1), Y{:Length}(2//1), Y{:Mass}(1//1), Y{:Time}(-2//1))}())
 Y{:Current}(-2//1)

edit: also happens on 0.7.0-DEV.554.

Even further:

  | | |_| | | | (_| |  |  Version 0.6.0-rc3.0 (2017-06-07 11:53 UTC)
 _/ |\__'_|_|_|\__'_|  |  Official http://julialang.org/ release
|__/                   |  x86_64-apple-darwin13.4.0

julia> map((1,)) do y
        print(STDOUT, " ")
        show(STDOUT, y)
       end
 1(nothing,)

julia> map((1,2)) do y
        print(STDOUT, " ")
        show(STDOUT, y)
       end
 1 2(nothing, nothing)

julia> map((1,2,3)) do y
        print(STDOUT, " ")
        show(STDOUT, y)
       end
 1 2 3(nothing, nothing, nothing)

julia> map((1,2,3,4)) do y
        print(STDOUT, " ")
        show(STDOUT, y)
       end
 1(nothing, nothing, nothing, nothing)

julia> map((1,2,3,4,5)) do y
        print(STDOUT, " ")
        show(STDOUT, y)
       end
 1 2(nothing, nothing, nothing, nothing, nothing)

julia> map((1,2,3,4,5,6)) do y
        print(STDOUT, " ")
        show(STDOUT, y)
       end
 1 2 3(nothing, nothing, nothing, nothing, nothing, nothing)

julia> map((1,2,3,4,5,6,7)) do y
        print(STDOUT, " ")
        show(STDOUT, y)
       end
 1 2 3 4(nothing, nothing, nothing, nothing, nothing, nothing, nothing)

It would seem that the last three elements of the tuple are not shown, provided the tuple is of length 4 or more, but the right number of nothings are collected in the returned tuple. If you map over an array instead of a tuple, you receive the correct output.

reducing even further, we see that arguments to _apply are simply forgotten:

julia> @noinline map3(f, t::Tuple{}) = ()
julia> @noinline map3(f, t::Tuple) = (f(t[1]), map3(f, Base.tail(t))...)
julia> @code_warntype map3((1, 2, 3, 4)) do y
           global niter += 1
           nothing
       end
Variables:
  #self#::#map3
  f::##107#108
  t::Tuple{Int64}

Body:
  begin
      $(Expr(:inbounds, false))
      # meta: location REPL[176] #107 2
      Main.niter = (Main.niter + 1)::Any
      # meta: pop location
      $(Expr(:inbounds, :pop))
      return (nothing,)
  end::Tuple{Void}

this is a pretty serious error, introduced by c562caa6f962ce7e49ef2bc361dad1c5e5ee4ffb

Are you already writing up a patch or should I?

Also, very very minor point: for side effects, use foreach instead of map.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tkoolen picture tkoolen  路  3Comments

ararslan picture ararslan  路  3Comments

StefanKarpinski picture StefanKarpinski  路  3Comments

felixrehren picture felixrehren  路  3Comments

manor picture manor  路  3Comments