Can anyone explain why these both compile happily :
data A a b = A { a :: a, b :: b }
newtype B a = B (A a (B a))
newtype C = C (A Int C)
B
This has to do with Equi-recursive types versus iso-recursive types. Haskell implements recursive types using iso-recursive types, which require the programmer to tell the type-checker when type recursion is happening. The way you mark it is with a specific constructor, which a simple type-synonym doesn't allow you to have.
Equi-recursive types allow the compiler to infer where recursion is happening, but it leads to a much more complicated type-checker and in some seemingly simple cases the problem is undecidable.
If you'd like a good discussion of equi vs. iso recursive types, check out Benjamin Pierce's excellent Types and Programming Languages
Short answer: because type synonyms don't introduce constructors, and haskell needs constructors to explicitly mark recursion at the type-level, you can't use recursive type synonyms.