@@ -880,6 +880,83 @@ Concretely, the structure of a `wit` file is:
880
880
wit-file ::= package-decl? (toplevel-use-item | interface-item | world-item)*
881
881
```
882
882
883
+ ### Feature Gates
884
+
885
+ Various WIT items can be "gated", to reflect the fact that the item is part of
886
+ an unstable feature or that the item was added as part of a minor version
887
+ update and shouldn't be used when targeting an earlier minor version.
888
+
889
+ For example, the following interface has 4 items, 3 of which are gated:
890
+ ``` wit
891
+ interface foo {
892
+ a: func();
893
+
894
+ @since(version = 0.2.1)
895
+ b: func();
896
+
897
+ @since(version = 0.2.2, feature = fancy-foo)
898
+ c: func();
899
+
900
+ @unstable(feature = fancier-foo)
901
+ d: func();
902
+ }
903
+ ```
904
+ The ` @since ` gate indicates that ` b ` and ` c ` were added as part of the ` 0.2.1 `
905
+ and ` 0.2.2 ` releases, resp. Thus, when building a component targeting, e.g.,
906
+ ` 0.2.1 ` , ` b ` can be used, but ` c ` cannot. An important expectation set by the
907
+ ` @since ` gate is that, once applied to an item, the item is not modified
908
+ incompatibly going forward (according to general semantic versioning rules).
909
+
910
+ In contrast, the ` @unstable ` gate on ` d ` indicates that ` d ` is part of the
911
+ ` fancier-foo ` feature that is still under active development and thus ` d ` may
912
+ change type or be removed at any time. An important expectation set by the
913
+ ` @unstable ` gate is that toolchains will not expose ` @unstable ` features by
914
+ default unless explicitly opted-into by the developer.
915
+
916
+ Together, these gates support a development flow in which new features start
917
+ with an ` @unstable ` gate while the details are still being hashed out. Then,
918
+ once the feature is stable (and, in a WASI context, voted upon), the
919
+ ` @unstable ` gate is switched to a ` @since ` gate. To enable a smooth transition
920
+ (during which producer toolchains are targeting a version earlier than the
921
+ ` @since ` -specified ` version ` ), the ` @since ` gate contains an optional ` feature `
922
+ field that, when present, says to enable the feature when * either* the target
923
+ version is greator-or-equal * or* the feature name is explicitly enabled by the
924
+ developer. Thus, ` c ` is enabled if the version is ` 0.2.2 ` or newer or the
925
+ ` fancy-foo ` feature is explicitly enabled by the developer. The ` feature ` field
926
+ can be removed once producer toolchains have updated their default version to
927
+ enable the feature by default.
928
+
929
+ Specifically, the syntax for feature gates is:
930
+ ``` wit
931
+ gate ::= unstable-gate
932
+ | since-gate
933
+ unstable-gate ::= '@unstable' '(' feature-field ')'
934
+ feature-field ::= 'feature' '=' id
935
+ since-gate ::= '@since' '(' 'version' '=' <valid semver> ( ',' feature-field )? ')'
936
+ ```
937
+
938
+ As part of WIT validation, any item that refers to another gated item must also
939
+ be compatibly gated. For example, this is an error:
940
+ ``` wit
941
+ interface i {
942
+ @since(version = 1.0.1)
943
+ type t1 = u32;
944
+
945
+ type t2 = t1; // error
946
+ }
947
+ ```
948
+ Additionally, if an item is * contained* by a gated item, it must also be
949
+ compatibly gated. For example, this is an error:
950
+ ``` wit
951
+ @since(version = 1.0.2)
952
+ interface i {
953
+ foo: func(); // error: no gate
954
+
955
+ @since(version = 1.0.1)
956
+ bar: func(); // also error: weaker gate
957
+ }
958
+ ```
959
+
883
960
## Package declaration
884
961
[ package declaration ] : #package-declaration
885
962
@@ -922,14 +999,21 @@ nesting both namespaces and packages, which would then generalize the syntax of
922
999
923
1000
## Item: ` world `
924
1001
925
- Worlds define a [ componenttype] ( https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md#type-definitions ) as a collection of imports and exports.
1002
+ Worlds define a [ ` componenttype ` ] as a collection of imports and exports, all
1003
+ of which can be gated.
926
1004
927
1005
Concretely, the structure of a world is:
928
1006
929
1007
``` ebnf
930
- world-item ::= 'world' id '{' world-items* '}'
1008
+ world-item ::= gate 'world' id '{' world-items* '}'
931
1009
932
- world-items ::= export-item | import-item | use-item | typedef-item | include-item
1010
+ world-items ::= gate world-definition
1011
+
1012
+ world-definition ::= export-item
1013
+ | import-item
1014
+ | use-item
1015
+ | typedef-item
1016
+ | include-item
933
1017
934
1018
export-item ::= 'export' id ':' extern-type
935
1019
| 'export' use-path ';'
@@ -944,6 +1028,8 @@ from the root of a component and used within functions imported and exported.
944
1028
The ` interface ` item here additionally defines the grammar for IDs used to refer
945
1029
to ` interface ` items.
946
1030
1031
+ [ `componenttype` ] : Explainer.md#type-definitions
1032
+
947
1033
## Item: ` include `
948
1034
949
1035
A ` include ` statement enables the union of the current world with another world. The structure of an ` include ` statement is:
@@ -966,18 +1052,20 @@ include-names-item ::= id 'as' id
966
1052
## Item: ` interface `
967
1053
968
1054
Interfaces can be defined in a ` wit ` file. Interfaces have a name and a
969
- sequence of items and functions.
1055
+ sequence of items and functions, all of which can be gated .
970
1056
971
1057
Specifically interfaces have the structure:
972
1058
973
1059
> ** Note** : The symbol ` ε ` , also known as Epsilon, denotes an empty string.
974
1060
975
1061
``` ebnf
976
- interface-item ::= 'interface' id '{' interface-items* '}'
1062
+ interface-item ::= gate 'interface' id '{' interface-items* '}'
977
1063
978
- interface-items ::= typedef-item
979
- | use-item
980
- | func-item
1064
+ interface-items ::= gate interface-definition
1065
+
1066
+ interface-definition ::= typedef-item
1067
+ | use-item
1068
+ | func-item
981
1069
982
1070
typedef-item ::= resource-item
983
1071
| variant-items
@@ -1002,6 +1090,7 @@ named-type-list ::= ϵ
1002
1090
named-type ::= id ':' ty
1003
1091
```
1004
1092
1093
+
1005
1094
## Item: ` use `
1006
1095
1007
1096
A ` use ` statement enables importing type or resource definitions from other
@@ -1631,3 +1720,46 @@ standalone interface definitions (such `wasi:http/handler`) are no longer in a
1631
1720
` use ` s are replaced by direct aliases to preceding type imports as determined
1632
1721
by the WIT resolution process.
1633
1722
1723
+ Unlike most other WIT constructs, the ` @since ` and ` @unstable ` gates are not
1724
+ represented in the component binary. Instead, they are considered "macro"
1725
+ constructs that take the place of maintaining two copies of a single WIT
1726
+ document. In particular, when encoding a collection of WIT documents into a
1727
+ binary, the target version and set of explicitly-enabled feature names
1728
+ determine whether individual gated features are included in the encoded type or
1729
+ not.
1730
+
1731
+ For example, the following WIT document:
1732
+ ``` wit
1733
+
1734
+
1735
+ interface i {
1736
+ f: func();
1737
+
1738
+ @since(version = 1.1.0)
1739
+ g: func();
1740
+ }
1741
+ ```
1742
+ is encoded as the following component when the target version is ` 1.0.0 ` :
1743
+ ``` wat
1744
+ (component
1745
+ (type (export "i") (component
1746
+ (export "ns:p/[email protected] " (instance
1747
+ (export "f" (func))
1748
+ ))
1749
+ ))
1750
+ )
1751
+ ```
1752
+ If the target version was instead ` 1.1.0 ` , the same WIT document would be
1753
+ encoded as:
1754
+ ``` wat
1755
+ (component
1756
+ (type (export "i") (component
1757
+ (export "ns:p/[email protected] " (instance
1758
+ (export "f" (func))
1759
+ (export "g" (func))
1760
+ ))
1761
+ ))
1762
+ )
1763
+ ```
1764
+ Thus, ` @since ` and ` @unstable ` gates are not part of the runtime semantics of
1765
+ components, just part of the source-level tooling for producing components.
0 commit comments