Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Precompilation affects function call in @generated function #19942

Closed
maleadt opened this issue Jan 9, 2017 · 6 comments
Closed

Precompilation affects function call in @generated function #19942

maleadt opened this issue Jan 9, 2017 · 6 comments
Assignees
Labels
bug Indicates an unexpected problem or unintended behavior types and dispatch Types, subtyping and method dispatch

Comments

@maleadt
Copy link
Member

maleadt commented Jan 9, 2017

Running into some #17057 complexity on latest master, where depending on the position in the source file / precompilation is on or off, a generated function selects a different method to call.

Foo/src/Foo.jl:

__precompile__()

module Foo

type Original end

end

Bar/src/Bar.jl:

__precompile__()

module Bar

using Foo

transform{T}(::Type{T}) = T

@generated function test()
    return transform(Foo.Original)
end

immutable Transformed end
transform(::Type{Foo.Original}) = Transformed

end

test.jl:

using Bar
@show Bar.test()

If I run this code as-is, I get the expected (to me) behaviour of the Original type getting transformed to Transformed:

$ JULIA_LOAD_PATH=. JULIA_PKGDIR=. julia test.jl
Bar.test() = Bar.Transformed

However, if I disable precompilation, it matches the first definition of transform:

$ JULIA_LOAD_PATH=. JULIA_PKGDIR=. julia --compilecache=no test.jl
Bar.test() = Foo.Original

This is further exemplified by removing the first transform definition:

$ JULIA_LOAD_PATH=. JULIA_PKGDIR=. julia --compilecache=no test.jl
ERROR: LoadError: MethodError: no method matching transform(::Type{Foo.Original})
The applicable method may be too new: running in world age 20564, while current world is 20566.
Closest candidates are:
  transform(::Type{Foo.Original}) at Bar/src/Bar.jl:14 (method too new to be called from this world context.)
Stacktrace:
 [1] test(...) at Bar/src/Bar.jl:10
 [2] include_from_node1(::String) at ./loading.jl:532
 [3] include(::String) at ./sysimg.jl:14
 [4] process_options(::Base.JLOptions) at ./client.jl:308
 [5] _start() at ./client.jl:374
while loading test.jl, in expression starting on line 229

This error does not show if I run with precompilation enabled. Furthermore, if I move the @generated function test below the additional definition of transform the issue disappears.
Also, on 0.5 everything works 'as expected' (ie. Transformed is returned in all cases, without errors)

@maleadt maleadt added bug Indicates an unexpected problem or unintended behavior types and dispatch Types, subtyping and method dispatch labels Jan 9, 2017
@yuyichao
Copy link
Contributor

yuyichao commented Jan 9, 2017

This appears to be documented.

Some operations that should not be attempted include:
....
Calling any function that is defined after the body of the generated function. This condition is relaxed for incrementally-loaded precompiled modules to allow calling any function in the module.

@maleadt
Copy link
Member Author

maleadt commented Jan 9, 2017

Ah, I was only looking at methods.md...
In my original use-case the transform function was called indirectly:

# package infrastructure

transform{T}(::Type{T}) = T
function transform_arguments(argtyp)
    return transform(argtyp)
end

@generated function entrypoint(args)
    transform_arguments(...)
end


# somewhere else (possibly user code)

type Something     end
type SomethingElse end
transform(::Type{Something}) = SomethingElse

I guess this falls under the same restriction?

@vtjnash
Copy link
Member

vtjnash commented Jan 9, 2017

Yes. As you can see, generated function are now prohibited from masquerading as memorization memoization routines.

@simonster
Copy link
Member

Does @pure (which does not appear to be documented at all) have the same restriction?

@vtjnash
Copy link
Member

vtjnash commented Mar 9, 2017

Officially undefined (in that it has been observed the behavior in this case is fairly unpredictable)

@cstjean
Copy link
Contributor

cstjean commented Jun 26, 2017

As you can see, generated function are now prohibited from masquerading as memorization memoization routines.

Unfortunately, this restriction also makes it hairy to write an extensible compiler for a DSL implemented with parametric types. I can't define new types and say compiler_treat_type_as_constant(::MyNewType) = true. The only way of passing information back is through inheritance 🙁

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Indicates an unexpected problem or unintended behavior types and dispatch Types, subtyping and method dispatch
Projects
None yet
Development

No branches or pull requests

5 participants