Maybe Haskell is the exception but I find it hard to believe that a compiler can do that for you, IMO, the only way to have a decent shot at being safe from XSS is to sanitize your inputs with a whitelist.
The compiler alone cannot do this, but the compiler combined with judicious use of the type system can. This is really the big value-add of Haskell/ML-style type systems; you can fit so many useful constraints into the type system that you can enlist the compiler into proving that you haven't made various common mistakes. If you can formalize an application logic error into a type error, you can use the compiler to enforce a wide variety of application logic error checking at compile time.
A simple example: suppose that every web form input is mapped into an "UnsafeUserInput rawtype" (that is, an algebraic data type parametrized over the raw input type). By simply ensuring that your output code only works on "SanitizedUserInput" types, you enforce that at some point in the code you apply a sanitization function to any unsafe input. Now the compiler is working for you, checking that your overall data flow respects the constraints you've encoded into the type system. In this style of programming, the type system becomes a way of encoding your desired integrity constraints inline with the functions and data types rather than outside the application logic in test suites.
http://blog.moertel.com/articles/2006/10/18/a-type-based-sol... is a very good read on the subject. basically, the compiler can have different types of strings, depending on where they come from, and how they are created. it can then make sure that different types of strings are never mixed without an explicit conversion operation. it is up to the programmer, of course, to see to it that that conversion operation involves sanitising, but the compiler will make sure you don't do
string a = get_input_from_user();
string b = sql_lookup(database, a);
insert_into_output_html(b);
requiring instead
UserInputString a = get_input_from_user();
SQLResultString b = sql_lookup(database, ConvertUserInputToSQLQueryInput(a))
insert_into_output_html(ConvertSQLResultToHtml(b));
(That was written over six years ago. Today, there are even better solutions that don't just apply static types to strings but to the language fragments within them.)
It's important to realize that safety is not a property of a string but a property of the relationship between a string and a use context. Thus all "solutions" that rely upon marking strings as clean work for only one kind of context. If you want a general solution, one that works for all injection problems, you have to be able to encode the full relationship model into the type system.