Skip to content

Wrong Type for ROUTER.add_route callback? #23818

@gatoWololo

Description

@gatoWololo

Background

I'm messing around with a typed version of the ipc::router::add_route method.
Original:

pub fn add_route(&self, receiver: OpaqueIpcReceiver, callback: RouterHandler)

// where
pub type RouterHandler = Box<FnMut(OpaqueIpcMessage) + Send>;

Mine:

pub fn add_route<T>(&self, receiver: IpcReceiver<T>,
                           mut callback: Box<FnMut(Result<T, ipc_channel::Error>) + Send>)

So I call the OpaqueIpcMessage::to message on behalf of the user, and hide all the implementations details about Opaque*.

When using the typed API I found two places in Servo where I couldn't get it to type check.

Actual Problem

From the latest master unmodified code. I'm looking at the function add_cache_listener_for_element in servo/components/script/dom/htmlimageelement.rs
The relevant parts are:

fn add_cache_listener_for_element(
            ...
            let (responder_sender, responder_receiver) = ipc::channel().unwrap();
            ...
            ROUTER.add_route(responder_receiver.to_opaque(), Box::new(move |message| {
                ...
                let image = message.to().unwrap();
                ...
                            element.process_image_response_for_environment_change(image, ...);
            ...
            }));

            image_cache.add_listener(id, ImageResponder::new(responder_sender, id));

Notice type inference is happening at two relevant places here: The type of channel<T>() and the type of to<T>(). I explicitly add a turbofish to channel:

- let (responder_sender, responder_receiver) = ipc::channel().unwrap();
+ let (responder_sender, responder_receiver) = ipc::channel::<PendingImageResponse>().unwrap();

I know this is the correct type from the call to ImageResponder::new(responder_sender, id)); at the bottom which takes the responder_sender: pub fn new(sender: IpcSender<PendingImageResponse>, ...) -> .... The compiler agrees with me, and type checks the program.

Now I try adding the type for the call to .to():

- let image = message.to().unwrap();
+ let image = message.to::<PendingImageResponse>().unwrap();

The message comes from the IpcReceiver<T> turned OpaqueReceiver. Which we have established has type PendingImageResponse. However, the way it is being using in the callback:

element.process_image_response_for_environment_change(image, ...);

The compiler infers:

    --> components/script/dom/htmlimageelement.rs:1012:83
     |
1012 |                             element.process_image_response_for_environment_change(image,
     |                                                                                   ^^^^^ expected enum `net_traits::image_cache::ImageResponse`, found struct `net_traits::image_cache::PendingImageResponse`
     |
     = note: expected type `net_traits::image_cache::ImageResponse`
                found type `net_traits::image_cache::PendingImageResponse`

This compiles fine without the added ::<PendingResponse> to to since the compiler infers the type should be ImageResponse. I believe this is wrong, and if this code were to be executed at runtime, the call to to().unwrap() would fail and panic?

Unless I'm missing some implicit conversion between ImageResponse and PendingImageResponse?

Metadata

Metadata

Assignees

No one assigned

    Labels

    I-papercutSmall but painful.I-safetySome piece of code violates memory safety guarantees.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions