Skip to content

Commit 07a62cc

Browse files
committed
Tighten versionsuffix rules and add WAST tests
Resolves #735
1 parent a25fc0b commit 07a62cc

6 files changed

Lines changed: 203 additions & 15 deletions

File tree

‎design/mvp/Binary.md‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -464,11 +464,12 @@ Notes:
464464
* 📡 Validation of `[set]` names requires that the function have either no
465465
result type or a result type of `(result (error $E)?)` (with no value type).
466466
* 🔀/📡 Functions with `[get]` or `[set]` names must not be `async`.
467-
* 🔗 Validation requires that `versionsuffix` is preceded by an `interfaceversion`
468-
matching `canonversion` and that the concatenation of the `canonversion` and
469-
the `versionsuffix` results in a `valid semver` as defined by
470-
[https://semver.org](https://semver.org/). A `versionsuffix` is otherwise
471-
ignored for validation except to improve diagnostic messages.
467+
* 🔗 Validation requires that a `versionsuffix` is only present when the
468+
`interfacename` has a `canonversion` and that the concatenation of the
469+
`canonversion` and the `versionsuffix`, if there is one, results in a
470+
`valid semver` as defined by [https://semver.org](https://semver.org/). A
471+
`versionsuffix` is otherwise ignored for validation except to improve
472+
diagnostic messages.
472473

473474
## 🪙 Value Definitions
474475

‎design/mvp/Explainer.md‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2988,12 +2988,13 @@ the `<major>.<minor>.<patch>(-<pre>)(+<build>)` syntax of [Semantic Versioning
29882988
- `0.0.1+sha.5114f85` &rarr; `0.0.1` / `+sha.5114f85`
29892989

29902990
When a version is canonicalized, any `semversuffix` that was split off of the
2991-
version should be preserved in the `versionsuffix` field of any resulting
2992-
`import`s and `export`s. This gives component runtimes and other tools access to
2993-
the original version for error messages, documentation, and other development
2994-
purposes. Where a `versionsuffix` is present the preceding `interfacename` must
2995-
have a `canonversion`, and the concatenation of the `canonversion` and
2996-
`versionsuffix` must be a `valid semver`.
2991+
version must be preserved in the `versionsuffix` field of any resulting
2992+
`import`s and `export`s to give component runtimes and other tools access to the
2993+
original version for error messages, documentation, and other development
2994+
purposes. Additionally, validation requires that the `canonversion` concatenated
2995+
with the `versionsuffix` (if present) is a `valid semver`. Where a
2996+
`versionsuffix` is present, the preceding `interfacename` must have a
2997+
`canonversion`.
29972998

29982999
For compatibility with older versions of this spec, non-canonical
29993000
`interfacename`s (with `interfaceversion`s matching any `valid semver`) are

‎test/README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ This directory contains Component Model reference tests, grouped by functionalit
66

77
A single `.wast` test can be run with full backtrace on trap via:
88
```
9-
WASMTIME_BACKTRACE_DETAILS=1 WAST_STRICT_COMPONENT_INDICES=1 wasmtime wast -W component-model-more-async-builtins -W component-model-threading -W component-model-async-stackful -W component-model-implements -W component-model-fixed-length-lists -W component-model-map the-test.wast
9+
WASMTIME_BACKTRACE_DETAILS=1 WAST_STRICT_COMPONENT_INDICES=1 wasmtime wast -W component-model-more-async-builtins -W component-model-threading -W component-model-async-stackful -W component-model-implements -W component-model-fixed-length-lists -W component-model-map -W component-model-canonical-names the-test.wast
1010
```
1111

1212
Sometimes test land ahead of the implementation and fail for a while. These
1313
tests are listed in 'nyi.txt' so that they can be filtered out. Thus, a simple
1414
way to run all the reference tests is:
1515
```
16-
find . -name "*.wast" | grep -vxFf nyi.txt | WAST_STRICT_COMPONENT_INDICES=1 xargs wasmtime wast -W component-model-more-async-builtins -W component-model-threading -W component-model-async-stackful -W component-model-implements -W component-model-fixed-length-lists -W component-model-map
16+
find . -name "*.wast" | grep -vxFf nyi.txt | WAST_STRICT_COMPONENT_INDICES=1 xargs wasmtime wast -W component-model-more-async-builtins -W component-model-threading -W component-model-async-stackful -W component-model-implements -W component-model-fixed-length-lists -W component-model-map -W component-model-canonical-names
1717
```

‎test/binary/binary.wast‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,15 +1308,21 @@
13081308
"\07\03" ;; type section (3 bytes)
13091309
"\01" ;; 1 type
13101310
"\42\00" ;; empty instancetype
1311-
"\0a\2f" ;; import section (47 bytes)
1312-
"\02" ;; 2 imports
1311+
"\0a\41" ;; import section (65 bytes)
1312+
"\03" ;; 3 imports
13131313
"\02" ;; externname with attributes
13141314
"\02i1" ;; name "i1"
13151315
"\01" ;; 1 attribute:
13161316
"\00" ;; 0x00 implements:
13171317
"\0cmy:dep/iface" ;; name "my:dep/iface"
13181318
"\05\00" ;; instance (type 0)
13191319
"\02" ;; externname with attributes
1320+
"\07a:b/c@1" ;; name "a:b/c@1"
1321+
"\01" ;; 1 attribute:
1322+
"\01" ;; 0x01 versionsuffix:
1323+
"\04.2.3" ;; ".2.3"
1324+
"\05\00" ;; instance (type 0)
1325+
"\02" ;; externname with attributes
13201326
"\02i2" ;; name "i2"
13211327
"\01" ;; 1 attribute:
13221328
"\02" ;; 0x02 external-id:

‎test/nyi.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
./values/post-return.wast
55
./async/big-interleaving-test.wast
66
./async/forward.wast
7+
./validation/version-suffix.wast
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
;; each case of the version splitting rules
2+
(component definition
3+
(import "a:b/c@1" (versionsuffix ".2.3") (instance)) ;; 1.2.3
4+
(import "a:b/d@1" (versionsuffix ".2.3+sha.5114f85") (instance)) ;; 1.2.3+sha.5114f85
5+
(import "a:b/e@10" (versionsuffix ".0.0") (instance)) ;; 10.0.0
6+
(import "a:b/f@0.2" (versionsuffix ".6") (instance)) ;; 0.2.6
7+
(import "a:b/g@0.2" (versionsuffix ".6+sha.5114f85") (instance)) ;; 0.2.6+sha.5114f85
8+
(import "a:b/h@0.10" (versionsuffix ".0") (instance)) ;; 0.10.0
9+
(import "a:b/i@0.0.1" (instance)) ;; 0.0.1
10+
(import "a:b/j@0.0.1" (versionsuffix "+sha.5114f85") (instance)) ;; 0.0.1+sha.5114f85
11+
(import "a:b/k@0.0.0" (instance)) ;; 0.0.0
12+
(import "a:b/l@0.0.12" (versionsuffix "+b") (instance)) ;; 0.0.12+b
13+
)
14+
15+
;; pre-release labels aren't split by canonicalization, but the concatenation is
16+
;; still a valid semver and thus valid
17+
(component definition
18+
(import "a:b/c@1" (versionsuffix ".2.3-alpha") (instance))
19+
(import "a:b/d@1" (versionsuffix ".2.3-alpha.1+sha") (instance))
20+
(import "a:b/e@0.0.1" (versionsuffix "-alpha") (instance))
21+
(import "a:b/f@0.0.1" (versionsuffix "-alpha+sha") (instance))
22+
)
23+
24+
;; an explicitly-empty versionsuffix is equivalent to no versionsuffix
25+
(component definition
26+
(import "a:b/c@0.0.1" (versionsuffix "") (instance))
27+
)
28+
29+
;; when canonversion is not itself a valid semver, a versionsuffix is required
30+
(assert_invalid
31+
(component (import "a:b/c@1" (instance)))
32+
"is not valid")
33+
(assert_invalid
34+
(component (import "a:b/c@0.2" (instance)))
35+
"is not valid")
36+
(assert_invalid
37+
(component (import "a:b/c@1" (versionsuffix "") (instance)))
38+
"is not valid")
39+
(assert_invalid
40+
(component (import "a:b/c@0.2" (versionsuffix "") (instance)))
41+
"is not valid")
42+
43+
;; the concatenation must be a valid semver
44+
(assert_invalid
45+
(component (import "a:b/c@1" (versionsuffix ".2") (instance)))
46+
"is not valid")
47+
(assert_invalid
48+
(component (import "a:b/c@1" (versionsuffix "+sha") (instance)))
49+
"is not valid")
50+
(assert_invalid
51+
(component (import "a:b/c@1" (versionsuffix "-alpha") (instance)))
52+
"is not valid")
53+
(assert_invalid
54+
(component (import "a:b/c@1" (versionsuffix "2.3") (instance)))
55+
"is not valid")
56+
(assert_invalid
57+
(component (import "a:b/c@1" (versionsuffix ".2.3.4") (instance)))
58+
"is not valid")
59+
60+
;; versions matching neither canonversion nor valid semver
61+
(assert_invalid
62+
(component (import "a:b/c@0" (versionsuffix ".1.0") (instance)))
63+
"is not valid")
64+
(assert_invalid
65+
(component (import "a:b/c@0.0" (versionsuffix ".1") (instance)))
66+
"is not valid")
67+
(assert_invalid
68+
(component (import "a:b/c@01" (versionsuffix ".2.3") (instance)))
69+
"is not valid")
70+
(assert_invalid
71+
(component (import "a:b/c@0.01" (versionsuffix ".3") (instance)))
72+
"is not valid")
73+
(assert_invalid
74+
(component (import "a:b/c@0.0.01" (instance)))
75+
"is not valid")
76+
77+
;; a versionsuffix requires an interfacename with a canonversion
78+
(assert_invalid
79+
(component (import "a" (versionsuffix ".2.3") (instance)))
80+
"is not valid")
81+
(assert_invalid
82+
(component (import "a" (versionsuffix "") (instance)))
83+
"is not valid")
84+
(assert_invalid
85+
(component (import "a:b/c" (versionsuffix ".2.3") (instance)))
86+
"is not valid")
87+
(assert_invalid
88+
(component (import "a:b/c" (versionsuffix "") (instance)))
89+
"is not valid")
90+
(assert_invalid
91+
(component (import "a:b/c@1.2.3" (versionsuffix "+sha") (instance)))
92+
"is not valid")
93+
(assert_invalid
94+
(component (import "a:b/c@1.2.3" (versionsuffix "") (instance)))
95+
"is not valid")
96+
(assert_invalid
97+
(component (import "a:b/c@0.2.6" (versionsuffix "+sha") (instance)))
98+
"is not valid")
99+
(assert_invalid
100+
(component (import "a:b/c@0.2.6" (versionsuffix "") (instance)))
101+
"is not valid")
102+
(assert_invalid
103+
(component (import "a:b/c@0.0.1-alpha" (versionsuffix "+sha") (instance)))
104+
"is not valid")
105+
(assert_invalid
106+
(component (import "a:b/c@0.0.1-alpha" (versionsuffix "") (instance)))
107+
"is not valid")
108+
109+
;; versionsuffix composes with external-id (in either order)
110+
(component definition
111+
(import "a:b/c@1" (versionsuffix ".2.3") (external-id "x") (instance))
112+
(import "a:b/d@1" (external-id "y") (versionsuffix ".2.3") (instance))
113+
)
114+
115+
;; versionsuffix is allowed in all import/export positions
116+
(component definition
117+
(import "a:b/i@0.2" (versionsuffix ".1") (instance $i
118+
(export "a:b/n@1" (versionsuffix ".0.0") (instance))
119+
))
120+
(export "a:b/i@0.3" (versionsuffix ".0") (instance $i))
121+
122+
(type (instance
123+
(export "a:b/c@1" (versionsuffix ".2.3") (instance))
124+
))
125+
(type (component
126+
(import "a:b/c@1" (versionsuffix ".2.3") (instance))
127+
(export "a:b/c@0.2" (versionsuffix ".6") (instance))
128+
))
129+
130+
(instance
131+
(export "a:b/i@1" (versionsuffix ".2.3") (instance $i))
132+
)
133+
(component $C (import "a:b/f@1" (versionsuffix ".0.0") (instance
134+
(export "a:b/g@1" (versionsuffix ".0.0") (instance))
135+
)))
136+
(instance (instantiate $C (with "a:b/f@1" (instance
137+
(export "a:b/g@1" (versionsuffix ".2.3") (instance $i))
138+
))))
139+
)
140+
141+
;; versionsuffix is ignored by name uniqueness...
142+
(assert_invalid
143+
(component
144+
(import "a:b/c@1" (versionsuffix ".2.3") (instance))
145+
(import "a:b/c@1" (versionsuffix ".4.5") (instance)))
146+
"conflicts with previous name")
147+
(assert_invalid
148+
(component
149+
(import "a:b/c@1" (versionsuffix ".2.3") (instance))
150+
(import "a:b/c@1" (versionsuffix ".2.3") (instance)))
151+
"conflicts with previous name")
152+
(assert_invalid
153+
(component
154+
(import "i" (instance))
155+
(export "a:b/c@0.2" (versionsuffix ".1") (instance 0))
156+
(export "a:b/c@0.2" (versionsuffix ".2") (instance 0)))
157+
"conflicts with previous name")
158+
159+
;; versionsuffix doesn't participate in type checking
160+
(component definition
161+
(import "s" (instance $s
162+
(export "a:b/e@1" (versionsuffix ".9.9") (instance))
163+
))
164+
(component $c
165+
(import "a:b/i@0.2" (versionsuffix ".1") (instance
166+
(export "a:b/e@1" (versionsuffix ".0.0") (instance))
167+
))
168+
)
169+
(instance (instantiate $c (with "a:b/i@0.2" (instance $s))))
170+
)
171+
(assert_invalid
172+
(component
173+
(import "s" (instance $s))
174+
(component $c
175+
(import "a:b/i@0.2" (versionsuffix ".1") (instance))
176+
)
177+
(instance (instantiate $c (with "a:b/i@0.2.1" (instance $s))))
178+
)
179+
"missing import named `a:b/i@0.2`")

0 commit comments

Comments
 (0)