-
Notifications
You must be signed in to change notification settings - Fork 136
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Looks into indirect types during compilation #2543
Looks into indirect types during compilation #2543
Conversation
from #543:
Actually, we already have much of what is needed to ignore missing types, specifically flag So rather than inventing much new, this change basically admits missing types throughout Now we need to make sure that any attempt to "use" a binary method with missing types is correctly detected, resulting in a proper error message, whereas missing types in irrelevant positions are simply ignored. Methods with a missing return type are already handled in For any missing parameter types I directly hooked into where types are used for applicability tests: Vararg invocations are already handled by the above, but inside TODOS:
|
parameterCompatibilityLevel(TypeBinding, TypeBinding, LookupEnvironment, boolean, MethodBinding)
Ergo, the following strategy seems to be complete:
|
fixes eclipse-jdt#543 + tolerate missing types during BTB.resolveTypesFor(MethodBinding) + new parameterCompatibilityLevel NEED_MISSING_TYPE + when NEED_MISSING_TYPE is encountered during resolution answer ProblemMethodBinding(ProblemReason.MissingTypeInSignature) + for varargs invocation try to discern if a missing type is relevant Tests: + adjust expected secondary errors (neither is better than the other) TODO: + check all call paths into parameterCompatibilityLevel() + fields
+ Java50Tests pointed to incomplete impl. at compliance below 1.8 => restrict new policy to 1.8+ + DependencyTests.testMissingClassFile() + bump test to 1.8 and let it include positive & negative cases + MultiProjectTests.test461074_error() split to 1.5 and 1.8 variants: + no change at 1.5 + no longer an error at 1.8+
- if in doubt signal "missing type" rather than plain "ambiguous"
b5b16e7
to
f474a32
Compare
Looking at the possible impact of a missing return type I think we can ignore the missing type in some situations: public class B {
public void A m() { return null; }
} When public class C {
void test(B b) {
b.m(); // no need to analyse A, right?
}
} The generated bytecode can still mention the full signature including the fully qualified name of type A, because that name is found in @srikanth-sankaran some questions:
WDYT? |
Here I was misled by
Lesson learned: ecj detects the wrong expression kind only after successful resolution, whereas javac seems to detect this based just on syntax. Setting VANILLA context for To fix this we can choose between setting expressionContext to @srikanth-sankaran TL;DR: of this comment: do you think we should complain about message send (and others?) in this position where a constant is expected ahead of resolution? |
+ ignore missing return type if not needed for further resolving - distinguish by expression context (vanilla -> not needed) - but for send in receiver position report despite vanilla context + avoid resolving MemberValuePair.value in expressionContext VANILLA
Sorry for the delay. I have finally started reviewing this. A rather naive question given the long history of this: what does javac do ? Is that captured somewhere ?? |
Short answer: I haven't checked, but perhaps we can just run the new tests with run.javac option enabled. I think the issue is less relevant for javac, since invocations of javac from a build system like maven tend to present all transitive dependencies on the classpath, so the situation of missing types would simply not occur. OSGi, however, has always distinguished between dependencies that are visible (re-exported) vs. invisible to clients, and that's what inspired the strategy for java projects in Eclipse and for ecj. With JPMS in the picture, this distinction would become relevant for javac, too. |
Results from running ProblemTypeAndMethodTest with 9 failures, 2 of which occur in new tests:
From the other failures only one looks remotely related:
Among the negative tests, where both ecj and javac report problems, javac sometimes reports "class file for p1.A not found" and sometimes reports incompatibilities like
where our new message would be more helpful: "The method m(Object) from the type B refers to the missing type A".
"cannot be converted" could actually be wrong. Perhaps A is indeed a subtype of the expected B, but we can't tell since A.class is missing. So overall compilers generally agree in which cases missing class files should be complained about. In the first part of testMissingClassNeededForOverloadResolution (compiling C.java) they agree to tolerate the missing class file. For the other two positive tests (testMissingClassNeededForOverloadResolution_varargs2 and testMissingClass_returnType_OK) the change would make ecj more tolerant than javac. |
Could you be more specific ? What do you mean by "some situations" - From the example you have cited and the mention of vanilla context I assume you mean calls where the return value is "dropped" - without assignment/return etc ? And where the return value does not serve as the reference for array indexing, method invocation, field access ?
Not at the outset. I would say we construct a special junit for all these cases and compare behavior with javac and use that as guiding principle.
I agree this is disruptive and best avoided.
How did you arrive at where it needs to be set from ? It appears you have zoomed into (I narrowed down on these two by a quick scan Expression's hierarchy.) In general what is the effect of
|
Is |
Can we have a brief solution statement ? It would be useful to have a write up that states in these limited scenarios, rather than issue a hard error about class path being incorrect, the compiler would tolerate missing class files. What would these be ? I know I can gather that from perusing various comments here in the PR and the github issue and by looking at the code changes, but it would help to have 4-6 line write up of the current stated objective of the fix - so I can see if that maps fully to the code changes bidirectionally |
org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/Scope.java
Show resolved
Hide resolved
...e.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LookupTest.java
Show resolved
Hide resolved
...core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SealedTypesTests.java
Show resolved
Hide resolved
org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/Scope.java
Outdated
Show resolved
Hide resolved
That would depend on how easy it is to do so. And if easy I would fork that work off to a different ticket. |
OK, I have made an initial pass over the changes and the commentary here and in the ticket. I will make one more pass tomorrow hopefully after getting some response to the questions raised in the interim. |
Reason for this request being some of the strategies/outline discussed in #543 (comment) appear outdated or disjoint from the code changes. This is perhaps due to the realization that various pieces of the puzzle already exist and can further be built upon ?? I am looking for something like: "When a class file referenced in a compilation mentions type names that are missing in the class path, tolerate the missing types if they feature in methods which are never seen to be invoked during the compilation of the sources, or if the missing types only feature in return types that are dropped or in variable arity situations unneeded actually to invoke the call." or something like that. That would help the next round of review and discussions. TIA
|
Start of piecemeal answers:
I agree to writing more junits, but I don't see, why javac should be the guiding principle in this matter. As outlined above, I believe Eclipse has a more vital interest to work with an incomplete classpath than javac. I'd love to see ecj more resilient in this matter, just we shouldn't produce wrong byte code.
good point. Will add it.
Thanks for the alert, this actually looks risky to me. How did you ensure that checks like I briefly considered an alternative design: what we need is similar to the flag
Most of these use the flag for optimizations in case of statics or constants (which I may or may not adopt for my case). Obviously I should add The specification to be implemented is a bit backwards: find all AST fields meeting both these criteria:
Does ===> Ergo: this little distinction is getting a bit convoluted. Perhaps the inverse of |
To me this question looks out-of place: the method is now The other change is, that the method is called from one more location.
The method asks a What am I missing? |
I suppose it is also true that |
org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/DependencyTests.java
Show resolved
Hide resolved
....compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java
Show resolved
Hide resolved
....core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
Show resolved
Hide resolved
[...]
When reviewing the underlying code earlier, I got the sense that we may not be fully evolving these as surrounding code evolves - the general issue could be addressed in #2651, but it is cool that these got caught already |
...ts.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProblemTypeAndMethodTest.java
Show resolved
Hide resolved
Perhaps more generally, I glanced through the numerous new tests in public void m(String s, MissingType m, Date d); and given call site --> m("Hello", new Object(), 42); So given two overloads, a first argument which is compatible with either method's first parameter and one candidate missing a type in second parameter position and third argument not compatible with the parameter of the method with the missing 2nd parameter, but compatible with the 3rd parameter of the other overload. |
....compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ParameterizedMethodBinding.java
Show resolved
Hide resolved
Status of review: Overall looks pretty good. Files yet to be reviewed: org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/Scope.java and a deeper check through: org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProblemTypeAndMethodTest.java I'll look at these first thing tomorrow morning. OK ? |
Right, |
Re tagging with
I feel that tagging and collecting are essential dual to each other, but in |
+ improve comment in DependencyTests + add more invocations in PTAMT.testMissingClassNeededForOverloadResolution_varargs1b + reject candidate meth by mismatching arg beyond a missing type param
This actually required a little fine tuning, but now we have testMissingClassNeededForOverloadResolution_pickByLateArg :) |
First thing in the morning: breakfast, or perhaps exercise. |
org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/Scope.java
Show resolved
Hide resolved
Did you mean "handling missing types doesn't look like an easy / big win" as opposed to " ignoring missing types doesn't look like an easy / big win" - we currently seem to ignore missing types here and bubble up |
My day officially starts only after exercise and breakfast my friend :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I only glanced through ProblemTypeAndMethodTest.java
but closely reviewed all other files. Looks pretty good to me! Comments uploaded for a few loose ends.
Both: we'd want to handle missing types in such a way that we can ignore those that have no impact on resolution :) |
+ more locations to propagate HasMissingType along w/ other tagBits
Interestingly, my last commit made JavaSearchBugsTests2.testBug123836c ff fail, such that an expected EXACT match is downgraded to POTENTIAL.
If I would eliminate the propagation type argument -> ParameterizedTypeBinding, then we would not get a match with receiver With this I believe the best way forward is
@srikanth-sankaran it looks like omitting the import in https://bugs.eclipse.org/123836 was not intended, right? |
+ revert duplicate tagging with HasMissingType (already in initialize()) + fix tests by adding required import + create one test variant with missing import and POTENTIAL_MATCH
I think so too. In all the additional variants of tests I have posted on that ticket Serializable is imported. In Markus's original comment#0 snippet the import is missing and it is captured as is. |
+ tolerate missing types during BTB.resolveTypesFor(MethodBinding) + new parameterCompatibilityLevel NEED_MISSING_TYPE + when NEED_MISSING_TYPE is encountered during resolution answer ProblemMethodBinding(ProblemReason.MissingTypeInSignature) + for varargs invocation try to discern if a missing type is relevant + detect when method return type can be ignored + detect missing types during type inference - don't let constraint with missing type fail type inference - prefer that candidate during overload resolution + let more locations propagate HasMissingType + improve collectMissingTypes() & protect against infinite recursion Tests: + adjust expected secondary errors (neither is better than the other) + Java50Tests pointed to incomplete impl. at compliance below 1.8 => restrict new policy to 1.8+ + DependencyTests.testMissingClassFile() + bump test to 1.8 and let it include positive & negative cases + MultiProjectTests.test461074_error() split to 1.5 and 1.8 variants: + no change at 1.5 + no longer an error at 1.8+ + improved errors in GenericsRegressionTest_1_8.testBug525580*() et al + fix JCL_LIB -> JCL18_LIB in ImportRewrite18Test + JavaSearchBugsTest2: - fix tests by adding required import - create one test variant with missing import and POTENTIAL_MATCH fixes eclipse-jdt#543
+ tolerate missing types during BTB.resolveTypesFor(MethodBinding) + new parameterCompatibilityLevel NEED_MISSING_TYPE + when NEED_MISSING_TYPE is encountered during resolution answer ProblemMethodBinding(ProblemReason.MissingTypeInSignature) + for varargs invocation try to discern if a missing type is relevant + detect when method return type can be ignored + detect missing types during type inference - don't let constraint with missing type fail type inference - prefer that candidate during overload resolution + let more locations propagate HasMissingType + improve collectMissingTypes() & protect against infinite recursion Tests: + adjust expected secondary errors (neither is better than the other) + Java50Tests pointed to incomplete impl. at compliance below 1.8 => restrict new policy to 1.8+ + DependencyTests.testMissingClassFile() + bump test to 1.8 and let it include positive & negative cases + MultiProjectTests.test461074_error() split to 1.5 and 1.8 variants: + no change at 1.5 + no longer an error at 1.8+ + improved errors in GenericsRegressionTest_1_8.testBug525580*() et al + fix JCL_LIB -> JCL18_LIB in ImportRewrite18Test + JavaSearchBugsTest2: - fix tests by adding required import - create one test variant with missing import and POTENTIAL_MATCH fixes eclipse-jdt#543
fixes #543
Tests:
Solution outline:
In short: we want to ignore all missing types that have no impact on invocation resolution, and we want to ignore missing return types if the return value is ignored.
In case invocation resolution involves type inference, we proceed like this:
TODO: