Your expectation is that when the compiler sees take_debug(by_val), it coerces by_val into an appropriate type. The problem is that it doesn’t know what type it’s supposed to coerce to. All it sees is this T thing, which it hasn’t assigned to a type yet.
So it assigns the only type is has on hand: fn(u32) {by_val}… which doesn’t implement Debug.
For this to work, the compiler would have to assign the type, fail to find the trait implementation, and then coerce the original input into a different type and re-try… possibly more than once. I dunno how I feel about that level of magic being involved.
take_fn is fine because there’s exactly coercion it can perform, so the behaviour is nice and simple.
As for ... as fn(_), all you’re doing there is explicitly triggering the conversion. Once it knows it has to coerce, it can fill in the argument types itself (which is what happens when it coerces for take_fn, and then infers the type of A).