As you seem to have found out, there's apparently two different ways that <:
can
be parsed, depending on context:
julia> using Base.Meta
julia> show_sexpr(:(S <: T))
(:comparison, :S, :<:, :T)
julia> show_sexpr(:(R <: S <: T))
(:comparison, :R, :<:, :S, :<:, :T)
julia> show_sexpr(:(type S <: T; end))
(:type, true, (:<:, :S, :T), (:block,))
julia> show_sexpr(:(f{S<:T}(::S) = 0))
(:(=), (:call, (:curly, :f, (:<:, :S, :T)), (:(::), :S)), 0)
It seems that the form with a :comparison head is used when <: is used as a
predicate, and the form with a <: head is used when declaring that a type
is a subtype of another. I am not sure if this has always been the case, or
if the parsing behavior for one of these changed at some point.
The AST printing was written to print illegal ASTs in a non-pretty way, to
make it easy to spot problems in generated ASTs. But this issue is hard
since there's apparently legitimate use for both cases. I guess the best
resolution would be to standardize on a single way to represent parsed <:
operators.