Why doesn't `@nospecialize` work in this example?

@nospecialize is targeted at the callee, but the caller is still allowed to try and guess what type is returned. It therefore doesn’t block inference directly, though loss of specialization can indirectly block inference. https://github.com/JuliaLang/julia/pull/41931

You might need Base.inferencebarrier:

julia> do_something_with_trait(x) = has_trait(typeof(Base.inferencebarrier(x))) ? "success" : "failure"
do_something_with_trait (generic function with 1 method)

julia> do_something_with_trait(Foo(1))
"success"

julia> do_something_with_trait(Foo("a"))
"success"

julia> methodinstances(has_trait)
2-element Vector{Core.MethodInstance}:
 MethodInstance for has_trait(::Type)
 MethodInstance for has_trait(::DataType)