script_bindings: Assert that serializable/transferable types have accurate WebIDL annotations (#38615)

These changes add compile-time assertions that:
* any type that implements the Serializable/Transferable trait has a
`[Serializable]` or `[Transferable]` annotation in the interface WebIDL
* any WebIDL interface with the `[Serializable]` or `[Transferable]`
annotation implements the corresponding trait

This is useful because it means that WebIDL definitions will be less
confusing if you're trying to figure out whether Servo supports
serializing/transferring a particular interface type. It also makes
fixing #21715 in the future a little bit easier, because the annotations
will remain up to date.

Testing: compile-time only; no point in writing tests for this since it
involves webidl codegen.

---------

Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
Josh Matthews 2025-08-13 04:36:04 -04:00 committed by GitHub
parent 0d6d434e59
commit bd9bb77295
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 84 additions and 27 deletions

View file

@ -2782,6 +2782,10 @@ def DomTypes(descriptors, descriptorProvider, dictionaries, callbacks, typedefs,
for parent in chain:
traits += [f"crate::conversions::DerivedFrom<Self::{parent}>"]
for marker in ["Serializable", "Transferable"]:
if descriptor.interface.getExtendedAttribute(marker):
traits += [f"crate::structuredclone::MarkedAs{marker}InIdl"]
iterableDecl = descriptor.interface.maplikeOrSetlikeOrIterable
if iterableDecl:
if iterableDecl.isMaplike():
@ -7609,6 +7613,28 @@ class CGRegisterProxyHandlers(CGThing):
return self.root.define()
class CGStructuredCloneMarker(CGThing):
"""
Generate a type assertion for inheritance
"""
def __init__(self, descriptor, marker):
CGThing.__init__(self)
self.descriptor = descriptor
self.marker = marker
self.marker_lower = marker.lower()
def define(self):
ifaceName = self.descriptor.interface.identifier.name
return f"""
impl script_bindings::structuredclone::MarkedAs{self.marker}InIdl for {ifaceName} {{
#[allow(path_statements)]
fn assert_{self.marker_lower}() {{
crate::dom::bindings::{self.marker_lower}::assert_{self.marker_lower}::<Self>;
}}
}}
"""
class CGConcreteBindingRoot(CGThing):
"""
Root codegen class for binding generation, specialized on the concrete
@ -7677,6 +7703,10 @@ class CGConcreteBindingRoot(CGThing):
),
]
for marker in ["Serializable", "Transferable"]:
if d.interface.getExtendedAttribute(marker):
cgthings += [CGStructuredCloneMarker(d, marker)]
if d.concrete:
if not d.interface.isIteratorInterface():
cgthings.append(CGAssertInheritance(d))