-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
type inference infinite loop #10340
Comments
@wbhart Can you create a minimal example that doesn't require building an external library? Preferably one that would fit in a single file? |
Also, why not use the julia promotion machinery? You could then use something like, +(x::RingElem, y::RingElem) = +(promote(x,y)...) |
Regarding the dependency on flint, this is a pretty complex library, and I don't think I can remove the dependency easily. However, from the point that t and u are created, at which point you can introspect the values and types easily, there is only two lines of code. So I don't think me spending a few days removing that dependency actually buys you anything. Were there problems building the external library on your machine? Note that Pkg.build("Nemo") should do all that automatically for you, at least on Linux. An important point I should have mentioned in the original bug report is this: Fraction is not used ever in any of the files loaded when you do using Nemo, except for where the type is (currently) defined in Rings.jl and in the single line of code in the failing example. In other words, the bug is this. I have working code, add a single new type definition, which is never used anywhere. Define a single addition operator for that type, and existing code breaks. That should not be possible under any circumstances. Regarding your question about why we don't use the promotion mechanism, we can't do that. A Julia type can't contain all the information we need. That's how the old Nemo worked, but people on the Julia list complained that we were using the type parameter and dispatch mechanisms for things that it wasn't designed for (which we were). Using parent objects, as opposed to Julia types is the only other way to model fully recursive parameterised mathematical types that I am aware of. This allows us to use Julia in a completely standard way whilst still retaining extra information about the "mathematical types" (parents) of objects that should not be pushed into the type parameters in Julia. |
The problem is that as the amount of effort required to reproduce the problem increases, the less likely that other people will be willing to put the effort into resolving the problem. I did actually get some sort of build error:
Ah, I see. |
Sure, I understand that. Fortunately, Pari is not needed. I will commit the following changes which will remove that dependency:
I'll check this works and commit in a minute or two. Hopefully you will at least be able to build it then. It would at least be good to have an independent replication of the bug. The alternative is probably me spending 2-3 days rewriting a large amount of code. I will if necessary, but just hoping I can possibly avoid it. There is another dispatch bug related to ccall anyway that I will report separately. So the effort of building the external library won't be wasted. |
I have now removed the pari dependency and verified the bug still exists. However, this was a very worthwhile exercise because I now have a stack trace, which will probably be a very big clue as to where the bug is in Julia: in typeinf at ./inference.jl:1625 This is the tail end of a few hundred pages of repetitious stack trace which just repeats over and over when I press CTRL-C to break out of the hang. Unfortunately there's more than 9999 lines of it, so I can't capture the start of the trace. |
Another perhaps relevant/interesting fact is that after breaking out of the hang, with that stack trace, issuing t + u again works fine. But then u + t fails to work, until I press CTRL-C, then both t + u and u + t work. The following may also be useful information:
That is all as I expect it to be, but it may be useful in tracking down the bug. I will shortly write a summary of the relevant parts of the type hierarchy that is being used here, so that it is perhaps easier to diagnose the problem. |
Here is a simplified summary of the type hierarchy being used here. I don't know if it is useful on its own without the supporting code to create values, but it might help in understanding what is actually being created here:
Note that FmpzPolyRing and PolynomialRing are for parent objects, which contain extra data we don't want to foist onto the Julia dispatch and dependent type mechanisms. Each polynomial object contains a "pointer" to its parent object, which gives rich mathematical type information (in this case just the ring on which it depends, which is another parent object for that ring). The definition of Fraction is as follows:
The FractionField type is for parent objects of an object of type Fraction. |
It seems to be more complicated than that: mine also hangs for |
That MAX_TYPE_DEPTH is the scariest thing I have seen in a very long time. By the way, the case where this was hit was a standard benchmark, which we On 27 February 2015 at 14:33, Isaiah notifications@github.com wrote:
|
No one can tell you if it is what you think it is without reading your mind, or at the very least more explanation of what you think it is. The general type inference problem is undecidable, since Julia's type system allows for the description of infinitely nested types. Any practical algorithm must necessarily give up somewhere, and |
On 27 February 2015 at 16:27, Jiahao Chen notifications@github.com wrote:
You can't read minds either? :-) I was really worried that this represents a hard limit on the depth of Julia types. I know type inference can hang if it doesn't give up. But I'm really hoping that "give up" doesn't entail not working at all. I guess I was also reacting to the fact that this must be set very low to
I didn't realise this would affect Julia. I was aware that global type inference is undecidable in the presence of And Julia knows the types of arguments to a function at runtime, in the Also inference in the presence of dependent types is undecidable if those So whilst I can understand Julia first trying to do some global type Sorry if this is all just completely wrong. I would actually really like to Please tell me I am worrying for nothing and that this behaviour is |
@simonbyrne I can confirm y + x does not work for me either, and I cannot even break out of the loop with CTRL-C. I am now actually a bit happier, as this is clearly not intended behaviour, as we aren't even two levels deep. It's a clear bug -- my guess is in Julia's type inference itself. |
Ok, I think the below is a minimal example that reproduces the bug. No external libraries are required. You can plug this code straight into Julia.
|
Thanks for the reduced test case. I'll work on this.
Quite right, but deciding when to bail is tricky, and here we are probably hanging on past the point when we should have bailed :) |
In trying to fix this I ended up fixing #1631 instead. |
That's really great news. I had been planning on reporting that one next if On 4 March 2015 at 22:21, Jeff Bezanson notifications@github.com wrote:
|
I believe this has the same root cause as #7534. |
@wbhart's test case appears be be fixed on latest master. Does this need a test before closing? |
Yes. |
I have encountered what I believe to be a bug in Julia's dispatch, which I haven't seen before.
When I add a completely unrelated method for the + operator, code that can't ever call the new + operator hangs. Remove the new + operator, everything is fine.
I've cut the issue down to a semiminimal example in:
https://github.com/wbhart/Nemo.jl/tree/polyaddbug
Note that the only files actually loaded are Nemo.jl, Rings.jl, Poly.jl, fmpz_poly.jl. I've moved the entire definition of the Fraction type into Rings.jl so that no addition files are actually loaded when using Nemo.
To build the cut down Nemo exhibiting the bug,
The following code will work:
However, the following code will not work (restart the REPL first):
You can inspect the types of t and u and they are most certainly not Fraction's, so t + u most definitely should not call the Fraction + operator.
The + it is supposed to call is the generic catchall in Rings.jl:
I can confirm that this generic catchall is called if you don't add the additional Fraction + operator above and it is not called if you do.
A hint is the fact that this behaviour only shows up 5 levels deep. Replacing t + u (types 5 levels deep) with z + t (types four levels) works just fine.
I'm using Julia Version 0.4.0-dev+2924.
The text was updated successfully, but these errors were encountered: