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.
This PR introduces abstract instance methods (like Java's
abstract
and C++'s pure virtuals) and abstract class methods to Flow. Abstractness on class methods sounds goofy from my Java and C++ intuitions, but ES6's prototype chaining on static methods (and Flow's enforcement of subtyping on those static methods) makes abstract class methods an expected feature beside abstract instance methods. In addition to the constraint on instantiation that abstract instance methods bring to Java and C++, abstract class methods bring in more constraints: No static methods can be called on an abstract class and its static fields can only be set.async
keyword is allowed on the abstract methods of classes (not declared classes). There's no function body for return value lifting, so it's just sugar.abstract
prefix on classes gets eaten for compatibility with TypeScript's abstract classes. The prefix doesn't alter Flow's behavior. My implementation diverges from TypeScript's in that TypeScript doesn't allow abstract static methods. This choice allows TypeScript to admit static method calls on abstract classes, whereas my implementation forbids such calls.abstract
again further down the inheritance chain.When I first saw the number of lines touched, I thought "holy crap." I then went through and counted the number of non-test lines touched:
Abstract static and non-static method parsing
: 969 lines,Abstract classes
: 1781 lines,Update extant parser tests
: 0 lines, andSupport optional abstract prefix on classes for TypeScript compatibility
: 5 linesThe PR is probably too huge in its current form for a merge, but can I negotiate a sequence of smaller pull requests working up to a final, abstract class PR? Or I could partition changes into commits with finer granularity? In particular:
src/parser/type_parser.ml
andsrc/parser/object_parser.ml
both parse classes and accumulate members while logging errors. I've introduced a functor to internalize accumulation and most of the error handling. See src/parser/object_members.ml, src/parser/type_parser.ml#L499-L535, and src/parser/object_parser.ml#L411-L514. This eliminates theerror_unexpected_variance
functions and their respective call sites intype_parser.ml
andobject_parser.ml
.SuperT
flow required theloc
s of full fields, not just those of the keys. This added another typical entry toType.Property.t
(beyondLoc.t option
andTypeTerm.t
). Bundling these typical entries into a tuple simplified a lot of the data processing insrc/typing/class_sig.ml
. Further, the introduction ofProperty.read: Property.t -> Property.triple
andProperty.write: Property.t -> Property.triple
simplified a few ugly pattern matches.fixes #3129 and fixes #5318