Repository navigation
fix: declare each method once, with a return type its supertypes accept - #90
Open
edusperoni wants to merge 2 commits into
Open
edusperoni wants to merge 2 commits into
edusperoni wants to merge 2 commits into
Conversation
A class lists the same JVM method several times: its own declaration, and that of every interface it or a class it extends implements. They were de-duplicated on their rendered text, so declarations that disagreed on nullability or parameter names all survived. Dialog declared both onCreatePanelView(featureId: number): View, its own unannotated method, and onCreatePanelView(param0: number): View | null, Window.Callback's @nullable one. AlertDialog, which only lists the interface's, was then not assignable to Dialog (TS2416), and every class carried a paramN copy of each interface method it implements. Declarations are now collected per JVM method. The return and each parameter are nullable if any declaration says so, and the declaration with parameter names is the one written. Methods that still render the same TypeScript are merged as before. TypeScript also lets an override narrow its return type but not widen it, so an override Java annotates @nullable cannot say so where a supertype declares the method non-null, which includes an unannotated one: AppCompatEditText.getText() against EditText.getText(). Its return is now declared non-null in that case. Supertypes are resolved through the input and --super jars, by the same rules as the supertype's own typings. On the android-37 platform jar this removes all 17 TS2416 errors (2 unrelated TS2417 remain) and 963 redundant lines from the AndroidX expected output, with no method lost from any class. Typings for kotlinx-coroutines, okhttp, okio, androidx and material go from 8 TS2416 errors to none, and Mapbox's from 24 to the 4 left between obfuscated Play Services classes, where a field and a method share a name. The AndroidX output now type-checks except for one error caused by the test running without android.jar, so the type check covers all of its errors instead of only syntax.
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the
|
…nherits When the declarations of one JVM method were merged, the one with parameter names replaced the rest outright, so a class whose own method has no LocalVariableTable (an abstract method, or bytecode compiled without -g) was rendered from an interface's default method, type variables included: Pipe<E>'s make(E, String) came out as make(fallback: any, tag: string): any. The class's own declaration now supplies the types and only the parameter names are borrowed. processMethod declares a superclass's method again in a class that declares another method of the same name. Those copies took the superclass method's raw annotation, which can differ from what the superclass's own typings declare once an interface's @nullable is merged in, so a subclass's override could still widen the copy's return type. The copies now take the superclass's declared nullability, and the supertype model counts them. With --merge-class-versions the model also counts the members only other versions of a class declare. Both cases are in the Kotlin fixture.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #89. It fixes the TS2416 errors that remained there: an override whose return type doesn't match the one its base class declares.
The problem
A class's typings list the same Java method several times: the class's own declaration, plus the declaration from every interface the class, or a class it extends, implements. These were de-duplicated by their rendered text, so copies that disagreed on nullability or parameter names all survived:
AlertDialogisn't assignable toDialog, becauseView | nulldoesn't fitDialog'sViewsignature (TS2416). Also, every class carried aparamNcopy of each interface method it implements.The fix
foo(int)andfoo(long)) are merged as before, together with their API-level tags.@Nullableis declared non-null too. An example isAppCompatEditText.getText()againstEditText.getText(). Supertypes are resolved through the input and--superjars, and their declared nullability is modelled from what their own typings list:--merge-class-versions, the members only other versions of the class declare.Dropping a
| nullis always valid TypeScript, so every direct supertype is consulted, not only the ones named inextends/implements.Parameters don't need the second rule: TypeScript compares method parameters in both directions.
Results
tsc 5.9,
strict,skipLibCheck: false:classfield)com.mapbox.maps:android:11.15.3+ dependencieszaa)test/expected-output)CommandProcessor.onCancelledvsAsyncTask; the test runs withoutandroid.jar, so the generator can't see the other overloadThe library rows were checked against platform typings generated by the same build. Other checks:
test/kotlin-fixturegainsOverrides.javacovering both patterns, plus the two cases an independent review found.mainfails on it.make test-typechecknow checks every error in the AndroidX output, not only syntax. The one knownAsyncTaskerror is listed incheck.mjswith the reason.Output changes
@Nullablebecome| nullon implementing classes too:Dialog.onCreatePanelView(...)now returnsView | null. That matches the interface's contract, but calling code may need a null check.@Nullablebut its supertype isn't, it's now declared non-null (e.g.AppCompatEditText.getText()). TypeScript has no way to express it otherwise.paramNnames disappear wherever the class declares the method itself.Known limits (all already present on
main)Iterator<String>.next()vsIterator.next()) have a different JVM descriptor from the method they override, so the rule doesn't connect them. Today these don't error, because the interface'sany-typed copy stays alongside as a separate overload.@Nullablestatic that hides an unannotated one in a superclass can still produce TS2417.implementation: {...}parameter of an interface's constructor still lists each declaration as written, so its nullability can differ from the class body's.zaa, TS2425), or a raw generic type left behind by a stripped signature (Spliterator, TS2314).