Skip to content

FlowLib: Add typed Set wrapper (#1940)#1940

Open
avp wants to merge 24 commits intofacebook:static_hfrom
avp:export-D96520014
Open

FlowLib: Add typed Set wrapper (#1940)#1940
avp wants to merge 24 commits intofacebook:static_hfrom
avp:export-D96520014

Conversation

@avp
Copy link
Contributor

@avp avp commented Mar 16, 2026

Summary:

Add a generic Set<T> to FlowLib that wraps the native Set
with typed add/has/delete/clear/forEach methods, allowing
typed code to use Set methods directly.

Differential Revision: D96520014

@meta-cla meta-cla bot added the CLA Signed Do not delete this pull request or issue due to inactivity. label Mar 16, 2026
@meta-codesync
Copy link

meta-codesync bot commented Mar 16, 2026

@avp has exported this pull request. If you are a Meta employee, you can view the originating Diff in D96520014.

avp and others added 12 commits March 16, 2026 16:29
Summary:
Add a function that allows users to query for a specific Decorator
pattern. This is used later to find specific Decorators during
typechecking.

Differential Revision: D92850438
Summary:
It's convenient to split this function up for future usage
and also for readability right now.

Differential Revision: D92435458
Summary:
We don't want to narrow to a non-single type using the simple version of
narrowing we have right now, because that results in a mismatch during
IRGen where FlowChecker thinks we have the narrowed type but we emit a
checked cast to the single type and then widen it again.

This results in types like `Foo | void` getting an IR type of `object`
instead of `object|undefined` and the output ends up completely
incorrect.

So prevent narrowing unless we're looking for a single type,
because that still handles the case we care about, where you can read a
property from an object even if the object is optional.

Differential Revision: D96500084
Summary:
Add support for generic methods on typed classes, with both
explicit type arguments and type inference at call sites. Add
the `Hermes.final` decorator and validate it in FlowChecker.

## Final Methods

`Hermes.final` bypasses the home object for
dispatch. Instead of loading the closure from the parent object
at the call site, a `Variable` is created in the enclosing
scope and the closure is stored there. At call sites, the
closure is loaded from the `Variable` via `LoadFrameInst`.

Non-final non-overridden methods continue to use
`TypedLoadParentInst` with a known `Function*` target.

## Generic Methods

Generic methods must be annotated `Hermes.final` because they
cannot participate in dynamic dispatch. Each call site is
specialized to a concrete function, so there is no
single function pointer to store in the vtable (home object).

## Decl and Variable storage during IRGen

`FlowChecker` creates a new `Decl` for each final method.
The callsites for final methods are annotated with the `Decl`
in the IdentifierNode, allowing us to find the Variable to load from.

At call sites, if the property `IdentifierNode` has a Decl, the closure
is loaded from the associated Variable directly, with a known call
target Function.

NOTE: Generic _private_ methods aren't supported yet because I wrote
this diff prior to adding support for private fields/methods, and
because this diff is big enough already.

Differential Revision: D92426451
Summary:
Optional parameters must appear last in the parameter list.

Update `canAFlowIntoB` for `TypedFunctionType` to allow flowing
between function types with different parameter counts when the
extra parameters are optional.

Insert an `ImplicitCheckedCast` when the parameter counts differ,
because we must prevent the user from casting away an optional parameter
then replacing it with an optional parameter of a different type!

Differential Revision: D92861947
Summary:
Implement typechecking for string property access:
- Named `.length` property returns number
- Computed index access with number returns string
- Error on non-number index or unknown property

This doesn't implement any special IRGen for faster reads yet,
just the type information.

String methods aren't supported yet either, those will be part of
however we do our typed JSLib.

NOTE: This is somewhat of a hack, but it's temporary while we figure
exactly how we want the indexed access JSLib functionality to work.

Differential Revision: D90788989
Summary:
To avoid dumping useless information from FlowLib,
set up the Sema dumper to dump only the relevant information for a given
function (and all lexical descendants). This way we can restrict what's
printed and avoid printing out the entire FlowLib just because it's in
the program.

This is very useful in future diffs due to the amount of Sema tests we
have and how many changes FlowLib changes will cause.

Differential Revision: D94141005
Summary:
Avoid dumping unnecessary info.

This reduces noise later.

Differential Revision: D94141003
Summary:
Add a FlowLib prelude mechanism for typed mode, analogous to
InternalJavaScript for the bytecode VM.

JS source files in `lib/FlowLib/` are sorted by their numeric prefix and
concatenated at build time into a single `FlowLib.js`. The source is
included directly in the compiled C++ code.

When typed mode wraps user code in an IIFE, the FlowLib source is parsed
and prepended as a prelude inside an outer IIFE. The resulting structure
is:
```
(function(){
  ...prelude...
  (function(exports){
    ...user code...
  })({})
})()
```
This way the user code can see the prelude but there won't be any naming
conflicts.

FlowLib is enabled in typed mode when std-globals are enabled.

NOTE: By default, `-dump-sema` now starts the dump from the inner
function (original user code) rather than the full wrapped program, so
tests don't include the FlowLib prelude or the outer IIFE wrapper. This
changed a lot of tests. If there's better ways to handle the tests here,
suggestions welcome.

Differential Revision: D91596589
Summary:
These are the first two functions we can add to the FlowLib.
`charAt` is an operation on a primitive, while `map` requires adding
`Array<T>`.

User code don't use these properly yet, that's in the next diff(s).

Differential Revision: D94141006
Summary:
Record the "builtin" directive for primitive JSLib functionality when
running SemanticResolver.

This isn't used yet.

Differential Revision: D91596590
Summary:
Resolve non-generic builtin method calls on
primitive types (string, e.g.) during type checking and IRGen.

`populateBuiltinMethods` scans functions marked with the "builtin"
directive and registers them in a table. MemberExpression visitors for
primitives can look up this table and store the resolved Decl.
CallExpression then calls resolveBuiltinMethodCall() to parse the
function type, set the callee type, and register the call target for
IRGen.

In IRGen, load the closure from the builtin's variable and emit
direct CallInst with the receiver and arguments.

NOTE: Right now this only works for `string`, but can be added for the
other primitives once they're in the FlowLib.

Differential Revision: D91519592
@meta-codesync meta-codesync bot changed the title FlowLib: Add typed Set wrapper FlowLib: Add typed Set wrapper (#1940) Mar 17, 2026
avp added a commit to avp/hermes that referenced this pull request Mar 17, 2026
Summary:
Pull Request resolved: facebook#1940

Add a generic `Set<T>` to FlowLib that wraps the native Set
with typed add/has/delete/clear/forEach methods, allowing
typed code to use Set methods directly.

Differential Revision: D96520014
@avp avp force-pushed the export-D96520014 branch from 8293c3f to 1b60c92 Compare March 17, 2026 16:57
avp added a commit to avp/hermes that referenced this pull request Mar 17, 2026
Summary:
Pull Request resolved: facebook#1940

Add a generic `Set<T>` to FlowLib that wraps the native Set
with typed add/has/delete/clear/forEach methods, allowing
typed code to use Set methods directly.

Differential Revision: D96520014
@avp avp force-pushed the export-D96520014 branch from 1b60c92 to 1128889 Compare March 17, 2026 21:19
avp added 9 commits March 18, 2026 10:48
Summary:
Handle `T[]` array types by resolving them to the corresponding
`Array<T>` generic class instantiation. Store a mapping from the
element type `T` to its `Array<T>` class so we can easily find the
relevant class.

`ArrayType` has not been completely removed yet to reduce the size of
this diff. I'll do that in a subsequent diff.

Add a parent/prototype pointer to `AllocFastArrayInst` /
`NewFastArray` so that created FastArrays point to the correct home
object (the `Array<T>` prototype). This is needed because home objects
are different between different generic class specializations (due to
copying the AST).

Array literals do not literally emit calls to the `Array<T>`
constructor. While it's conceptually cleaner in IRGen, that would
require varargs support and sophisticated optimizations to ultimately
reach `NewFastArray` which is what we want to actually emit without any
extra indirections. Instead, we directly generate the IR we want at the
callsite.

Introduce an `InferencePlaceholder` specifically for arrays,
because arrays are the only structural type that can be inferred but
is represented by a `ClassType` internally. This avoids regressing any
type inference behavior.

Differential Revision: D94096273
Differential Revision: D94141004
Summary:
Add some more array functions to the FlowLib.
Update widgets accordingly.

Differential Revision: D94149418
Summary:
Add `staticObjectType_` to `ClassType` to represent the static
side of a class. Static fields and methods are lowered to `Variable`s
rather than object layout slots.

FlowChecker resolves member access on `ClassConstructorType`
by looking up the static object type, validates static field/
method override compatibility against the superclass, and
uses `classConsType` to set the correct `this` type
for static methods.

IRGen emits static fields/methods as Variables during
`genClassDeclaration` and handles private static names via
`PrivateNameNode` unwrapping.

This diff has to support:
* public and private static fields
* public and private static methods
* generic public static methods
* static inheritance

NOTE: This doesn't support private static generic methods yet,
because generic private methods in general are not supported yet.
That will be added in the next diff(s).

Differential Revision: D95152702
Summary:
Previously, generic private methods were errors. This diff
supports them by using the method call handling already in place for
public generics.

FlowChecker: The duplicated code paths for `ClassType` and
`ClassConstructorType` are merged into a single flow that looks up the
method via `findPublicField` or `findPrivateField` based on whether the
callee is a `PrivateNameNode`.

IRGen: private generic methods are skipped during regular private
method emission, and `genSpecializedMethods` now handles private keys by
generating the correct private name identifier.

Differential Revision: D95858239
Summary:
This adds default parameter handling in two places:
- Marks them as optional in the function type,
  enabling correct typechecking.
- Sets the parameter's declared type (non-optional inside the body) and
  typechecks the default value expression against the declared type.

Differential Revision: D96830016
Summary:
When a destructuring pattern has a type annotation
pass the resolved type as the constraint to the initializer
expression. This lets the checker infer array literals as
tuples instead of arrays.

Previously the constraint was only extracted for simple
identifier declarations, leaving it null for array/object
patterns and failing to typecheck.

Differential Revision: D96835196
Summary:
Add type-checking for destructuring parameters in typed functions.

Require type annotations on destructuring patterns, propagate types
to leaf identifiers, and refactor tuple/object destructuring expansion
into shared helpers.

There's not a lot of new code here, but there was some refactoring and
function extraction to avoid having too much duplication.

Differential Revision: D96961531
Summary:
Previously this was unsupported.
We can add it, just need to support knowing the actual type of the
inherited constructor.

Differential Revision: D97012043
avp and others added 3 commits March 18, 2026 10:48
Summary: Also update widgets accordingly.

Differential Revision: D97124221
Summary:
Add a generic `Map<K, V>` to FlowLib that wraps the native Map
with typed methods, allowing typed code to use
map.get()/map.set() directly instead of using hacks.

Update the widgets benchmark and test to use the new typed Map. Removing
the mapPrototypeGet/mapPrototypeSet hacks and use proper generic types.

Differential Revision: D96520015
Summary:
Pull Request resolved: facebook#1940

Add a generic `Set<T>` to FlowLib that wraps the native Set
with typed add/has/delete/clear/forEach methods, allowing
typed code to use Set methods directly.

Differential Revision: D96520014
@avp avp force-pushed the export-D96520014 branch from 1128889 to 67b9fda Compare March 18, 2026 17:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed Do not delete this pull request or issue due to inactivity. fb-exported meta-exported

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant