Skip to content

Add type parameter support for built-in functions. #1249

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

Merged
merged 7 commits into from
Nov 13, 2023

Conversation

nevkontakte
Copy link
Member

For many built-ins the behavior differs depending on their argument types. In such cases, each relevant type constructor has a method implementing the built-in for that specific type, e.g. for a slice t of type T, expression len(t) will translate into something like T.$len(t). In some cases, where it doesn't seem performance-critical, I changed the whole implementation of the built-in to use this mechanism, even if no type parameters are involved to reduce the amount of duplicated logic.

Some functions like append() or delete() put sufficiently strict constraints on the type parameter to not require runtime dispatch. In those cases I only had to tweak the code a bit to correctly identify types.

Updates #1013.

Slice, channel and map types' constructors now have a .make() method
that implements the builtin for the corresponding type. The compiler
simply calls the builtin without a need to introspect the type.
Similar to make(), each relevant type constructor has a $len() method
that takes an unwrapped type value and returns its length. Whenever
len() is called with a type param, the compiler emits a call to
`Type.$len(value)`.

Unlike make(), I kept compile-time specializations of len(), since they
are much more likely to be called in performance-critical path and would
be cheaper than a call to `T.$len()`.
%f instructs the format to "flatten" all numeric types into a JS number.
To do that correctly, you need to know whether the passed number is
64-bit or less. In case of the type parameter we pass the type
constructor as a second argument to determine that at runtime.
Similar to len(), to maintain performance when used in loops I've kept
compile-time specializations for when the exact type is known.
Otherwise, a type-specific implementation is called at runtime.
For the most part it already worked through the $newDataPointer(), I
only had to update it to handle pointers to array, which are a wrapped
type.
Instead of interrogating the type of the slice or map expression passed
to the built-in, we interrogate types of the computed built-in
signature. In case of append(), it will be a slice of element types due
to variadic nature of the built-in. For map it will be the plain key
type. We can then use that type to translate expressing with implicit
conversion.
@nevkontakte nevkontakte requested a review from flimzy November 12, 2023 20:05
@nevkontakte nevkontakte merged commit b123493 into gopherjs:generics Nov 13, 2023
@nevkontakte nevkontakte deleted the generics16 branch November 13, 2023 21:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants