Description
Consider the following example:
void main() {
final fn_expr_block_body = () {
return 0;
};
final fn_expr_expr_body = () => 0;
int fn_block_body() {
return 0;
}
int fn_expr_body() => 0;
}
int top_fn_block_body() {
return 0;
}
int top_fn_expr_body() => 0;
This example presents different ways for declaring function-like constructs. All of them have in common that they provide the ability to encapsulate either a sequence of statements (via block bodies) or a single expression (via expression bodies).
Return types tell the compiler that the body of a function needs to return an expression of a specific type, or more generally, the return type can be seen as an annotation that requires the body of the function to pass certain analyses.
Unfortunately, Dart does not provide a uniform mechanism for adding custom annotations to all such statement/expression encapsulating constructs. Such annotations would be needed to inform static analysis tools about the fact that the user wishes for additional constraints to be satisfied.
Proposal
This issue proposes for Dart to support custom metadata annotations on function expression bodies and function block bodies.
(TODO the grammar changes need to be worked out)
This is what the example from above could look like with custom metadata annotations.
void main() {
final fn_expr_block_body = () @pure {
return 0;
};
final fn_expr_expr_body = () @pure => 0;
int fn_block_body() @pure {
return 0;
}
int fn_expr_body() @pure => 0;
}
Future<int> top_fn_block_body() async @pure {
return 0;
}
int top_fn_expr_body() @pure => 0;
const pure = Pure();
class Pure {
const Pure();
}
This would allow tool developers to add support for additional analyses related to function bodies without having to rely on comments. The main motivation for this issue is to add metadata support to IIFEs in a way that is uniform with other function-like constructs.
To further motivate this issue, here are some answers to: 'What could metadata in these positions be used for?'
Verifying local purity
To add the constraint that all references can only refer to the immediate function parameters or global declarations.
const c = 0;
void main() {
final a = 0;
int f(int b) @localpure {
// 'a' can't be accessed in a locally pure function.
// v
return a + b + c;
}
}
Verifying total purity
To add the constraint that all references can only refer to the immediate function parameters.
const c = 0;
void main() {
final a = 0;
final f = (int b) @totalpure {
// 'c' can't be accessed in a totally pure function.
// v
// 'a' can't be accessed in a totally pure function.
// v
return a + b + c;
}
}
Secure typing
To add secure typing-like constraints to all function-like constructs without having to rely on comments as metadata.