Skip to content

Commit 8626cd5

Browse files
authored
fix(validators): ensure cached values of dictionaryIncludesRequiredField are boolean (#546)
The two `return true` statements would leave undefined in the cache, and looking up the same dictionary again would then return undefined instead of true. The bug manifests when the same dictionary appears as an argument twice or more. Fixes #545.
1 parent a19d359 commit 8626cd5

File tree

3 files changed

+16
-12
lines changed

3 files changed

+16
-12
lines changed

lib/validators/helpers.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,17 +62,19 @@ export function dictionaryIncludesRequiredField(dict, defs) {
6262
if (defs.cache.dictionaryIncludesRequiredField.has(dict)) {
6363
return defs.cache.dictionaryIncludesRequiredField.get(dict);
6464
}
65-
defs.cache.dictionaryIncludesRequiredField.set(dict, undefined); // indeterminate
66-
if (dict.inheritance) {
65+
// Set cached result to indeterminate to short-circuit circular definitions.
66+
// The final result will be updated to true or false.
67+
defs.cache.dictionaryIncludesRequiredField.set(dict, undefined);
68+
let result = dict.members.some(field => field.required);
69+
if (!result && dict.inheritance) {
6770
const superdict = defs.unique.get(dict.inheritance);
6871
if (!superdict) {
69-
return true;
70-
}
71-
if (dictionaryIncludesRequiredField(superdict, defs)) {
72-
return true;
72+
// Assume required members in the supertype if it is unknown.
73+
result = true;
74+
} else if (dictionaryIncludesRequiredField(superdict, defs)) {
75+
result = true;
7376
}
7477
}
75-
const result = dict.members.some(field => field.required);
7678
defs.cache.dictionaryIncludesRequiredField.set(dict, result);
7779
return result;
7880
}
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
(dict-arg-optional) Validation error at line 25 in argument-dict-optional.webidl, inside `interface mixin Container -> operation op1 -> argument shouldBeOptional`:
22
undefined op1(Optional shouldBeOptional);
33
^ Dictionary argument must be optional if it has no required fields
4-
(dict-arg-optional) Validation error at line 29 in argument-dict-optional.webidl, inside `interface mixin Container -> operation op3 -> argument union`:
4+
(dict-arg-optional) Validation error at line 31 in argument-dict-optional.webidl, inside `interface mixin Container -> operation op3 -> argument union`:
55
(Optional or boolean) union);
66
^ Dictionary argument must be optional if it has no required fields
7-
(dict-arg-optional) Validation error at line 30 in argument-dict-optional.webidl, inside `interface mixin Container -> operation op4 -> argument union`:
7+
(dict-arg-optional) Validation error at line 32 in argument-dict-optional.webidl, inside `interface mixin Container -> operation op4 -> argument union`:
88
undefined op4(OptionalUnion union);
99
^ Dictionary argument must be optional if it has no required fields
10-
(dict-arg-optional) Validation error at line 33 in argument-dict-optional.webidl, inside `interface mixin Container -> operation op6 -> argument recursive`:
10+
(dict-arg-optional) Validation error at line 35 in argument-dict-optional.webidl, inside `interface mixin Container -> operation op6 -> argument recursive`:
1111
undefined op6(Recursive recursive);
1212
^ Dictionary argument must be optional if it has no required fields
13-
(dict-arg-optional) Validation error at line 36 in argument-dict-optional.webidl, inside `interface mixin Container -> operation op8 -> argument lastRequired`:
13+
(dict-arg-optional) Validation error at line 38 in argument-dict-optional.webidl, inside `interface mixin Container -> operation op8 -> argument lastRequired`:
1414
undefined op8(Optional lastRequired, optional DOMString yay
1515
^ Dictionary argument must be optional if it has no required fields
16-
(dict-arg-optional) Validation error at line 42 in argument-dict-optional.webidl, inside `interface ContainerInterface -> iterable -> argument shouldBeOptional`:
16+
(dict-arg-optional) Validation error at line 44 in argument-dict-optional.webidl, inside `interface ContainerInterface -> iterable -> argument shouldBeOptional`:
1717
<DOMString>(Optional shouldBeOptional);
1818
^ Dictionary argument must be optional if it has no required fields

test/invalid/idl/argument-dict-optional.webidl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ interface mixin Container {
2525
undefined op1(Optional shouldBeOptional);
2626
undefined op2(Required noNeedToBeOptional);
2727
undefined op22(Required2 noNeedToBeOptional);
28+
// The same again to expose caching bug:
29+
undefined op23(Required2 noNeedToBeOptional);
2830

2931
undefined op3((Optional or boolean) union);
3032
undefined op4(OptionalUnion union);

0 commit comments

Comments
 (0)