-
-
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
Stopgap for Vararg widening #11480
Stopgap for Vararg widening #11480
Conversation
This is a not-very-good fix for the following problem. It turns out that since Vararg is a type (which I would argue is a bad idea), it can get widened into a `<:Vararg` type var. This is not handled correctly and can cause inference to crash. This patch does not fix the fact that we could potentially encouter something like `Tuple{<:Any}` which could come from `Tuple{Vararg{T}}`.
Well, I completely agree this is not a very good fix :)
That is funny, because in #10380 I initially implemented exactly that, then later undid it. It turned out to be a big pain. Instead of looking for The big question is how this relates to #11242. I agree If you want to change this, we need ideas for what the syntax and internal representation should be for I think we should just fix all the cases that handle Vararg wrong, such as the widening case you mention. |
80b0032 might achieve the same thing? |
yeah consider this PR a bug report but since I had to dirty fix it to find out what was wrong with the code that tripped up inference... I'll believe you that it is too much of a pain to have info outside parameters (there must be at least one downside to have Tuple::DataType after all). I think the core of the problem is what is If we on the other hand we want to have Vararg be more "special", i.e., whenever inference instantiate a Tuple type, it knows whether it's a Vararg or not, then you have to forbid it from being a type parameter I think, and pretty much anywhere we could "hide" it. I'm glad to see that your PR fixed this issue already @timholy. I think there may be a few other places where it's possible to hide a Vararg or a Type{Vararg} that we should be careful with. E.g. this segfaults on master (didn't try your branch) : type B{T}; x::T; end
function f(x::B,z)
y :: Tuple{x.x} = z
y[2]
end
b = B{Type}(Vararg{Int})
@show code_typed(f, (typeof(b),Tuple{Int,Int}))
f(b,(1,2)) (inference only sees Tuple{::Type{T}} and does not consider the T=Vararg{S} case) I'll try to think of other problems. |
Yes, cases like that are not intended to be allowed. We should disallow more things, like substituting The big problem is the metaprogramming case where you have I definitely see why making this part of the tuple type feels safer. But it means that the programmer is forced to write out, with a branch, the analysis type inference would ideally do:
|
I think we could allow it in TypeVar bounds, and it could be "useful", as long as the getfield function is careful. If for example we implement one day the old abstract A{T}
tmerge(A{Tuple{Vararg{Int}}}, A{Tuple{Vararg{Float}}}) === A{Tuple{<:Vararg{<:Real}}} Anyway, I would argue that most uses of isvatuple should be using getfield_tfunc instead. In fact, isvatuple is correct if one considers it an abstract predicate where false means Top. It probably should be named isknownlength or something, to be consistent with issubtype. So that !isknownlength does not allow you to go picking manually at the last argument without checking that it is actually a Vararg{T}. |
No, I don't think we want it in TypeVar bounds. The covariance of Tuples makes that unnecessary; the type in your example could be written as |
Right. So the only question is whether The other possibility is to have the checks be done on |
I should think more before posting, forget about the second possibility it would be obviously a huge mess for any tuple with an Any type at the end. We'll just have to be careful when constructing tuple types then. |
i think this is also related to #10930 |
possibly related to #16530 also? |
This PR probably can't be applied anymore, but this is still a potential bug. |
Yes, there are still some bugs here. What I'd do is
Currently we think this always returns some subtype of |
- fix #11480, don't use `Type{_} where _<:Vararg` in inference - disallow `Vararg` in type var bounds - disallow `Vararg` as a type parameter in general - move some checks from lower-level functions to apply_type
- fix #11480, don't use `Type{_} where _<:Vararg` in inference - disallow `Vararg` in type var bounds - disallow `Vararg` as a type parameter in general - move some checks from lower-level functions to apply_type
This is a not-very-good fix for the following problem. It turns out that
since Vararg is a type (which I would argue is a bad idea), it can get
widened into a
<:Vararg
type var. This is not handled correctly andcan cause inference to crash. This patch does not fix the fact that we
could potentially encouter something like
Tuple{<:Any}
which couldcome from
Tuple{Vararg{T}}
.A small repro :
I would argue that
Vararg
as a type has to go away, since being handled as a special case everywhere it breaks some obvious rules like :My vote is for Vararg to be a syntactic-only construct that can never be materialized outside of a tuple type. It would be a property of the tuple type alone.
cc @JeffBezanson