[compiler] Functions, reborn#9060
Merged
witemple-msft merged 83 commits intomicrosoft:mainfrom Feb 25, 2026
Merged
Conversation
302d35b to
09fa854
Compare
Member
Author
|
Companion PR is passing: Azure/typespec-azure#3865 |
timotheeguerin
approved these changes
Feb 25, 2026
github-merge-queue bot
pushed a commit
to Azure/typespec-azure
that referenced
this pull request
Feb 25, 2026
This is an integration PR for changes related to microsoft/typespec#9060 ([compiler] Functions, reborn). - TCGC: loosened an exhaustiveness check around Value kinds in `getValueTypeValue`. - Generally: regenerated `generated-defs` which now exports decorators as `_decs` rather than `_` and will generate function definitions if any are declared.
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.
This PR implements
fnin TypeSpec. Functions are like decorators in that they are callable entities bound to implementations through the TypeSpec JavaScript host function interface.Functions are declared using
extern fnand must bind to an implementation declared through a$functionsexport in a JS source file.Functions accept and produce entities. Value arguments to functions are converted to JS values like decorator arguments are, and the inverse is also true for functions: returned JS values are converted to TSP Value entities through an "unmarshaling" process. This allows the implementation to be natural for JS developers while integrating with the TSP value space.
Functions are values, not types. They can be assigned to
constdeclarations. The result of calling a function can be either a Type or a Value, but the function itself is a value.Functions can have a return type constraint. The default return type constraint of a function, if none is specified, is
unknown. Functions can also returnvoid, in which case JS functions that returnundefinedare specially accepted as if they returnedvoidType. This allows JS void functions to bind naturally to TypeSpec functions that returnvoid.Functions calls are evaluated at check-time. When a
CallExpressionis checked, where the callee is an instance ofFunctionValue:CallExpressionchecking result is the unmarshaled entity.Functions support mixed constraints (
Type | valueof Type) in both parameter and return position.Like decorators, functions cannot serve as regular types and are only allowed to appear when resolving the target of a
CallExpression.model Foo { p: f }wherefis aFunctionTypeis not allowed, butmodel Foo { p: f() }is.Unlike decorators, function host bindings MUST use
$functions. Bare exported functions are not bound to JS source files.Functions appear in the type graph as
functionDeclarationson a Namespace. The semantic walker has been updated to visit FunctionValue declarations.TSPD is updated to generate extern signatures for functions, like decorators.
In addition to function declarations, this PR also adds syntax for function types. A function type is the signature of a function and does not contain an implementation (it is not unique to a particular function declaration). Function types are only assignable to other function types and to the top type
unknown. A function type is a type expression of the grammatical form'fn' '(' ParameterList? ')' ('=>' MixedConstraint)?. Like with a function declaration, the return type is implicitlyunknownif not specified. Function types observe strict assignability rules that obey contravariance over parameter assignability. A function type F1 is assignable to a function type F2 if:Parameter assignability is determined by an algorithm that guarantees that each parameter in the source function (which is the target of parameter assignability) is satisfied by a corresponding parameter in the target function (which is the source of parameter assignability), given the following rules:
...rest: T[]) of array typeT[], then the type U of each subsequent parameter in the source parameter list (required, optional, or rest item) must be assignable to type T.Notably:
fn (x: valueof string)does NOT assign tofn(...rest: valueof string[]). TypeScript allows this, but it creates soundness problems that we will need to be aware of if we decide to relax this restriction in the future.