Fix for issue #497.  Reviewed by gwt.team.mmendez
http://code.google.com/p/google-web-toolkit/issues/detail?id=497

This is one of the most subtle compiler issues I've ever debugged.  The 
following sequence of events triggers the problem described in the issue.  
Assume Foo is a class that implements IFoo.

1) MakeCallsStatic creates a static implementation "Foo.$foo()" of 
instance method "Foo.foo()"; tthis moves the body of foo() into $foo(), 
and replaces the body of foo() with a call to $foo()
2) MethodInliner inlines calls to Foo.$foo() at all call sites, including 
the call from Foo.foo()
3) Pruner prunes Foo.$foo(), because it's been inlined everywhere, there 
are no outstanding calls to it
4) More optimizations occur which allow an IFoo type variable to be 
tightened to a Foo type variables.
5) MakeCallsStatic sees the tightened variable and statically resolves an 
IFoo.foo() call to a Foo.$foo(); unfortunately, $foo() has already been 
pruned and there is no process for unpruning
6) For various reasons, the new call to Foo.$foo() does not get inlined at 
the new call site (this is a rare case, that it would get inlined 
everywhere else, but not here).
7) Foo.$foo() does not get visited during GenerateJavaScriptAST (because 
it's pruned); the outstanding non-inlined call to it causes a compiler 
error.

My solution addresses step #3 in the problem chain.  I modified Pruner so 
that Foo.$foo() will not pruned as long as Foo.foo() is live, even if 
Foo.$foo() has been inlined into Foo.foo().  On the final pruning pass, we 
will go ahead and prune Foo.$foo() if it's unreferenced.  By that time, 
MakeCallsStatic will never run again because all optimizations will 
be done.

However, having $foo() in limbo for some time raised a couple of issues.  
I discovered that all of its parameters were being tightening to null, 
which led me to two observations.

1) It doesn't make sense to nullflow an unreferenced parameter.  Period.  
Unlike fields & locals, there is never an implicit null initialization; 
the value has to come from SOMEWHERE.

2) It doesn't make sense to make Foo.$foo()'s params tighter than 
foo()'s params as long as foo() is still live.  This is because 
some call site currently pointing to foo() may change and point at 
$foo() later, meaning $foo()'s params are now invalidly too tight.  
So I made a special case upref from $foo() to foo(), which makes sense 
because the normal case is explicit type flow from foo() to $foo() when 
inlining does not occur.

I fixed both of the above issues in TypeTightener.

I also changed the semantics of the return value of 
tryInlineSimpleMethodCall to differentiate between methods that cannot be 
inlined (even in theory) and methods that cannot be inlined at this 
particular call site.  This prevents a caching bug where a failure to 
inline at one site would prevent you from even trying at other sites.

There are also a couple of field sorts mixed into this patch.




git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@220 8db76d5a-ed1c-0410-87a9-c151d255dfc7
4 files changed