RFR: 8303526: Changing "arbitrary" Name.compareTo() ordering breaks the regression suite [v2]

Vicente Romero vromero at openjdk.org
Mon Mar 27 20:07:50 UTC 2023


On Tue, 21 Mar 2023 23:06:48 GMT, Archie L. Cobbs <duke at openjdk.org> wrote:

>> This was discovered during investigation for [JDK-8268622](https://bugs.openjdk.org/browse/JDK-8268622).
>> 
>> The method `Name.compareTo()` looks like this:
>> 
>> /** An arbitrary but consistent complete order among all Names.
>>  */
>> public int compareTo(Name other) {
>>     return other.getIndex() - this.getIndex();
>> }
>> 
>> Note the "arbitrary but consistent" wording. Unfortunately, the ordering can be "arbitrary" only if you don't mind breaking the regression suite.
>> 
>> For example, if you apply this patch:
>> 
>> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Name.java
>> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Name.java
>> @@ -105,7 +105,7 @@ public abstract class Name implements javax.lang.model.element.Name, PoolConstan
>>      /** An arbitrary but consistent complete order among all Names.
>>       */
>>      public int compareTo(Name other) {
>> -        return other.getIndex() - this.getIndex();
>> +        return this.getIndex() - other.getIndex();
>>      }
>> 
>>      /** Return true if this is the empty name.
>> 
>> then the following tests will fail:
>> ```TEST: tools/javac/8203436/T8203436b.java
>> TEST: tools/javac/generics/7034019/T7034019c.java
>> TEST: tools/javac/generics/7034019/T7034019d.java
>> TEST: tools/javac/generics/diamond/neg/Neg21.java
>> TEST: tools/javac/generics/diamond/neg/Neg22.java
>> TEST: tools/javac/generics/inference/EagerReturnTypeResolution/EagerReturnTypeResolutionTestb.java
>> TEST: tools/javac/patterns/InferenceUnitTest.java
>> TEST: tools/javac/T8187978/FilterOutCandidatesForDiagnosticsTest.java
>> TEST: tools/javac/varargs/6806876/T6806876.java
>> 
>> ==============================
>> Test summary
>> ==============================
>>    TEST                                              TOTAL  PASS  FAIL ERROR
>>>> jtreg:test/langtools:langtools_javac               3718  3709     9     0 <<
>> ==============================
>> 
>> The compiler behavior should be deterministic whenever possible, and the javac regression suite should be robust. So clearly "arbitrary" behavior by this method is not really supported.
>> 
>> It turns out there is only one user of `Name.compareTo()`, the method `TypeSymbol.precedes()`:
>> 
>> /**
>>  * A partial ordering between type symbols that refines the
>>  * class inheritance graph.
>>  *
>>  * Type variables always precede other kinds of symbols.
>>  */
>> public final boolean precedes(TypeSymbol that, Types types) {
>>     if (this == that)
>>         return false;
>>     if (type.hasTag(that.type.getTag())) {
>>         if (type.hasTag(CLASS)) {
>>             return
>>                 types.rank(that.type) < types.rank(this.type) ||
>>                 types.rank(that.type) == types.rank(this.type) &&
>>                 that.getQualifiedName().compareTo(this.getQualifiedName()) < 0;
>>         } else if (type.hasTag(TYPEVAR)) {
>>             return types.isSubtype(this.type, that.type);
>>         }
>>     }
>>     return type.hasTag(TYPEVAR);
>> }
>> 
>> If we want the above partial ordering to be stable, we need to specify deterministic behavior for `Name.compareTo()`.
>> 
>> An obvious choice would be to require that `Name.compareTo()` orders consistently with `String.compareTo()`, i.e., lexicographically on the Unicode characters in the name.
>> 
>> Fortunately, this comparison can be done efficiently, i.e., without actually converting the `Name` into a `String`, because UTF-8 is "lexicographically consistent" with the characters it encodes, except that Java's use of Modified UTF-8 means a special check for 0x0000 (which is encoded as two bytes) is required.
>> 
>> When you do this the tests are still broken... but notice that `TypeSymbol.precedes()` is actually using the _reverse_ of `Name.compareTo()`. So somehow, the current `Name.compareTo()` is ordering things "backwards", at least from the point of view of the expectation of the regression tests.
>> 
>> So replacing `Name.compareTo()` with a version that orders lexicographically, and also un-reversing its treatment in `TypeSymbol.precedes()`, makes things the tests succeed again.
>> 
>> That's what this patch does.
>
> Archie L. Cobbs has updated the pull request with a new target base due to a merge or a rebase. The pull request now contains two commits:
> 
>  - Merge branch 'master' into JDK-8303526
>  - Require Name.compareTo() to produce a lexicographic ordering.

looks good

-------------

Marked as reviewed by vromero (Reviewer).

PR Review: https://git.openjdk.org/jdk/pull/12843#pullrequestreview-1359792282


More information about the compiler-dev mailing list