Where {T<:ConcreteType}

Should n’t the two methods of f in the example below conflict?

abstract type AbstractA end
struct A <: AbstractA
    data::Int
end
f(a::T) where {T<:A} = (T, a.data)
f(A(2))
# (A, 2)
f(a::A) = ("A", a.data)
f(A(2))
# ("A", 2)

I also see that when the methods are declared in the reverse order the second one does not have any effect.

abstract type AbstractA end
struct A <: AbstractA
    data::Int
end
f(a::A) = ("A", a.data)
f(A(2))
# ("A", 2)
f(a::T) where {T<:A} = (T, a.data)
f(A(2))
# ("A", 2)

When is the latter invoked ever?

My understanding is that the latter will never be invoked because it is being “masked” by the former. Ideally it would give some sort of warning when you define the latter, but I don’t know how complicated it would be to do the code analysis necessary to generate the appropriate warnings in the general case.

It used to. The warnings got intentionally removed except for when precompiling.