mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 1819215 - wasm: Change subtyping rules for functions. r=rhunt
Previously, function subtyping was only checking the invariance. Now, return types are covariant and arguments are contravariant. Differential Revision: https://phabricator.services.mozilla.com/D175697
This commit is contained in:
parent
a49062ba28
commit
7390510f3f
79
js/src/jit-test/tests/wasm/gc/function_subtyping.js
Normal file
79
js/src/jit-test/tests/wasm/gc/function_subtyping.js
Normal file
@ -0,0 +1,79 @@
|
||||
// |jit-test| skip-if: !wasmGcEnabled()
|
||||
|
||||
// Validate rules for function subtyping:
|
||||
// - Same number of parameters and results
|
||||
// - Function return types are covariant
|
||||
// - Function parameter types are contravariant
|
||||
wasmValidateText(
|
||||
`(module
|
||||
(type $A (struct (field i32)))
|
||||
(type $B (sub $A (struct (field i32) (field i32))))
|
||||
(type $C (sub $B (struct (field i32) (field i32) (field i64))))
|
||||
(type $D (sub $B (struct (field i32) (field i32) (field f32))))
|
||||
|
||||
;; Same types (invariant)
|
||||
(type $func1 (func (param (ref $A) (ref $A)) (result (ref $C))))
|
||||
(type $func2 (sub $func1 (func (param (ref $A) (ref $A)) (result (ref $C)))))
|
||||
|
||||
;; Covariant return types are valid
|
||||
(type $func3 (func (param (ref $A) (ref $A)) (result (ref $B))))
|
||||
(type $func4 (sub $func3 (func (param (ref $A) (ref $A)) (result (ref $C)))))
|
||||
(type $func5 (func (param (ref $A) (ref $A)) (result (ref $A) (ref $B))))
|
||||
(type $func6 (sub $func5 (func (param (ref $A) (ref $A)) (result (ref $D) (ref $C)))))
|
||||
|
||||
;; Contravariant parameter types are valid
|
||||
(type $func7 (func (param (ref $A) (ref $C)) (result (ref $C))))
|
||||
(type $func8 (sub $func7 (func (param (ref $A) (ref $B)) (result (ref $C)))))
|
||||
(type $func9 (func (param (ref $D) (ref $C)) (result (ref $C))))
|
||||
(type $func10 (sub $func9 (func (param (ref $A) (ref $B)) (result (ref $C)))))
|
||||
|
||||
;; Mixing covariance and contravariance
|
||||
(type $func11 (func (param (ref $D) (ref $C)) (result (ref $A))))
|
||||
(type $func12 (sub $func11 (func (param (ref $A) (ref $B)) (result (ref $C)))))
|
||||
)
|
||||
`);
|
||||
|
||||
// Validate that incorrect subtyping examples are failing as expected
|
||||
const typeError = /incompatible super type/;
|
||||
|
||||
var code =`
|
||||
(module
|
||||
(type $A (struct (field i32)))
|
||||
(type $B (sub $A (struct (field i32) (field i32))))
|
||||
(type $C (sub $B (struct (field i32) (field i32) (field i64))))
|
||||
(type $D (sub $B (struct (field i32) (field i32) (field f32))))
|
||||
|
||||
;; Not the same number of arguments/results
|
||||
(type $func1 (func (param (ref $A) (ref $A)) (result (ref $C))))
|
||||
(type $func2 (sub $func1 (func (param (ref $A) (ref $A)) (result (ref $C) (ref $A)))))
|
||||
)`;
|
||||
|
||||
wasmFailValidateText(code, typeError);
|
||||
|
||||
code =`
|
||||
(module
|
||||
(type $A (struct (field i32)))
|
||||
(type $B (sub $A (struct (field i32) (field i32))))
|
||||
(type $C (sub $B (struct (field i32) (field i32) (field i64))))
|
||||
(type $D (sub $B (struct (field i32) (field i32) (field f32))))
|
||||
|
||||
;; Contravariant result types are invalid
|
||||
(type $func3 (func (param (ref $A) (ref $A)) (result (ref $C))))
|
||||
(type $func4 (sub $func3 (func (param (ref $A) (ref $A)) (result (ref $A)))))
|
||||
)`;
|
||||
|
||||
wasmFailValidateText(code, typeError);
|
||||
|
||||
code =`
|
||||
(module
|
||||
(type $A (struct (field i32)))
|
||||
(type $B (sub $A (struct (field i32) (field i32))))
|
||||
(type $C (sub $B (struct (field i32) (field i32) (field i64))))
|
||||
(type $D (sub $B (struct (field i32) (field i32) (field f32))))
|
||||
|
||||
;; Covariant parameters are invalid
|
||||
(type $func5 (func (param (ref $A) (ref $A)) (result (ref $C))))
|
||||
(type $func6 (sub $func5 (func (param (ref $B) (ref $A)) (result (ref $C)))))
|
||||
)`;
|
||||
|
||||
wasmFailValidateText(code, typeError);
|
@ -189,8 +189,31 @@ class FuncType {
|
||||
// relationship.
|
||||
static bool canBeSubTypeOf(const FuncType& subType,
|
||||
const FuncType& superType) {
|
||||
// Temporarily only support equality for function subtyping
|
||||
return FuncType::strictlyEquals(subType, superType);
|
||||
// A subtype must have exactly as many arguments as its supertype
|
||||
if (subType.args().length() != superType.args().length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// A subtype must have exactly as many returns as its supertype
|
||||
if (subType.results().length() != superType.results().length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Function result types are covariant
|
||||
for (uint32_t i = 0; i < superType.results().length(); i++) {
|
||||
if (!ValType::isSubTypeOf(subType.results()[i], superType.results()[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Function argument types are contravariant
|
||||
for (uint32_t i = 0; i < superType.args().length(); i++) {
|
||||
if (!ValType::isSubTypeOf(superType.args()[i], subType.args()[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool canHaveJitEntry() const;
|
||||
|
Loading…
Reference in New Issue
Block a user