We've known for a while that the GWT compiler is spammy, even at default log
levels. There is a reason for this behavior, believe it or not: TypeOracle's
JClassType#getSubtypes() call. Because generators can ask for the subtypes
of any type, the compiler has to parse essentially everything, not just
those types that are statically reachable from a module's entry point(s). We
sometimes refer to it as "speculative parsing." Overall, the behavior is
vitally useful for code generators, especially RPC and I18n, and it's
generally useful anytime you need to do something factory-like, where you
might have used Class.forName() if it were available. So, I'm not proposing
that we change that behavior. The problem is that in the process of
speculatively parsing everything on the client source path, inevitably we
end up encountering source files that can't actually be meaninfully compiled
given the current client source path and other various reasons for
mismatches. It can happen when you have more than one <module>.gwt.xml in
the same location with different sets of inherited modules.
We ought to find a way to keep quieter about problems we find during that
speculative parse. We want to *not* spam the log when the source file was
found "speculatively" but definitely still report errors when they really
are relevant to getting a clean compile.

This isn't as simple as it might sound. It isn't just a "how do we code it"
question. Imagine you have a GWT module that needs RPC. Because RPC can use
polymorphism, you might have an RPC method whose return type is "Shape" (vs.
concrete subtypes Circle, Square, Triangle). This is handled magically in
the GWT RPC generator because it can see those subtypes of Shape and quietly
generate deserializers in the generated RPC proxy. The tricky bit is when
Circle.java has a syntax error, say. The type "Circle" won't be found as a
subtype of Shape in the type oracle, so the GWT RPC generator won't know to
emit a deserializer for it. (To be precise, it won't even know that it
*ought* to try to do so.) We have a choice: either we emit a string of
non-fatal errors regarding the failure to parse Circle.java or we don't. If
we do, we get the spam we hate today, but at least we've informed the
developer that something fishy may happen, since it wasn't a perfectly clean
compile. If we don't emit such errors, then a module will quietly appear to
compile, even when there are compilation problems that might affect the
intended behavior (in this case, when a server responds to the client with a
Circle object, the client won't know how to deserialize it).

All that said, I don't think it will be big a problem in practice if we log
less and risk the kind of surprise failure I described with something like
RPC. After all, javac (or your IDE) would complain about Cirlce.java not
compiling anyway, so the only real failure mode happens if you *only*
compile with the GWT compiler -- and that seems pretty unlikely, especially
if you're working in an IDE.

Here's a proposal for the new behavior. When the GWT compile invokes JDT to
do the front-end compile, capture the errors in an in-memory data structure
(keyed by type name?) but do not log them right away. After the JDT
front-end compile settles, create a set of "known statically reachable"
types from the entry point classes (the entry point classes are reachable
from themselves by definition). Only log errors on compilation unit in that
set of dependencies, and do not log errors in an other case.

Anybody see any problems with this idea? I think this would omit log
messages that make you say, "What on earth does NumberFormat_fr_Test.java
have to do with my compiling Hello.java?"

-- Bruce

--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/Google-Web-Toolkit-Contributors
-~----------~----~----~----~------~----~------~--~---

Reply via email to