Cannot understand why E0277 is triggered here:

Along the lines of my question on deref coercion:

I'd like to understand why the following code doesn't work:

pub struct TTestSyncClient {
  i_prot: Rc<RefCell<Box<TProtocol>>>,
  o_prot: Rc<RefCell<Box<TProtocol>>>,
  sequence_number: i32,
}

impl TTestSyncClient {
  fn send_testVoid(&mut self) -> rift::Result<()> {
    self.sequence_number = self.sequence_number + 1;
    let message_ident = TMessageIdentifier { name:"testVoid".to_owned(), message_type: TMessageType::Call, sequence_number: self.sequence_number };
    let call_args = testVoid_args {  };
    try!(self.o_prot.borrow_mut().write_message_begin(&message_ident));
    try!(call_args.write_to_out_protocol(&mut self.o_prot.borrow_mut())); // <-- ERROR HERE
    try!(self.o_prot.borrow_mut().write_message_end());
    Ok(())
  }
  fn recv_testVoid(&mut self) -> rift::Result<()> {
    let message_ident = try!(self.i_prot.borrow_mut().read_message_begin());
    try!(verify_expected_sequence_number(self.sequence_number, message_ident.sequence_number));
    try!(verify_expected_service_call("testVoid", &message_ident.name));
    try!(verify_expected_message_type(TMessageType::Reply, message_ident.message_type));
    let result = try!(testVoid_result::read_from_in_protocol(&mut self.i_prot.borrow_mut())); // <-- ERROR HERE
    try!(self.i_prot.borrow_mut().read_message_end());
    result.ok_or()
  }
}

#[derive(Debug)]
struct testVoid_args {
}

impl testVoid_args {
  fn read_from_in_protocol<P: TProtocol>(i_prot: &mut P) -> rift::Result<testVoid_args> {
    try!(i_prot.read_struct_begin());
    loop {
      let field_ident = try!(i_prot.read_field_begin());
      if field_ident.field_type == TType::Stop {
        break;
      }
      let field_id = try!(field_id(&field_ident));
      match field_id {
        _ => {
          try!(i_prot.skip(field_ident.field_type));
        },
      }
    }
    try!(i_prot.read_struct_end());
    let ret = testVoid_args {};
    Ok(ret)
  }
  fn write_to_out_protocol<P: TProtocol>(&self, o_prot: &mut P) -> rift::Result<()> {
    let struct_ident = TStructIdentifier { name: "testVoid_args".to_owned() };
    try!(o_prot.write_struct_begin(&struct_ident));
    try!(o_prot.write_field_stop());
    try!(o_prot.write_struct_end());
    try!(o_prot.flush());
    Ok(())
  }
}

Spitting out the error:

/*
error[E0277]: the trait bound `std::cell::RefMut<'_, Box<rift::protocol::TProtocol + 'static>>: rift::protocol::TProtocol` is not satisfied
    --> src/rift_test.rs:2313:20
     |
2313 |     try!(call_args.write_to_out_protocol(&mut self.o_prot.borrow_mut()));
     |                    ^^^^^^^^^^^^^^^^^^^^^ trait `std::cell::RefMut<'_, Box<rift::protocol::TProtocol + 'static>>: rift::protocol::TProtocol` not satisfied
error[E0277]: the trait bound `std::cell::RefMut<'_, Box<rift::protocol::TProtocol + 'static>>: rift::protocol::TProtocol` is not satisfied
    --> src/rift_test.rs:2322:23
     |
2322 |     let result = try!(testVoid_result::read_from_in_protocol(&mut self.i_prot.borrow_mut()));
     |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `std::cell::RefMut<'_, Box<rift::protocol::TProtocol + 'static>>: rift::protocol::TProtocol` not satisfied
     |
     = note: required by `rift_test::testVoid_result::read_from_in_protocol`
*/

The message seems to imply that the RefMut<Box>> is not being derefed, and I don't understand why.

Note that a helpful soul on IRC showed me how to work around the error (example here), but neither of us understands why the caller has to explicitly dereference twice.

The message seems to imply that the RefMut<Box>> is not being derefed, and I don't understand why.

Correct. It's not being derefed, because there's nothing to cause it to be derefed. The compiler only derefs in two situations: when it's looking for a field/member via dot member access, and when trying to coerce a borrowed pointer. That's it.

Note that neither of those apply here: the function you're calling wants a &mut T, and you're giving it a &mut T. The problem is that RefMut<_> doesn't satisfy the constraint RefMut<_>: TProtocol, hence the error.

To put it another way: Rust won't deref something to try and satisfy constraints.

1 Like

This one snagged me too a while back. Here's a simpler case:

use std::fmt::Debug;

struct S(i32);
impl std::ops::Deref for S {
    type Target = i32;
    fn deref(&self) -> &i32 { &self.0 }
}

fn concrete(t: &i32)         { println!("{:?}", t); }
fn variable<T: Debug>(t: &T) { println!("{:?}", t); }
fn object(t: &Debug)         { println!("{:?}", t); }

#[test]
fn no_coercion_for_bounds() {
    let s = S(10);
    concrete(&s);

    // error[E0277]: the trait bound `S: std::fmt::Debug` is not satisfied
    // variable(&s);
    // object(&s);
    
    // These work fine, because the `as` expression forces
    // the `Deref` coercions. Then `T: Debug` is satisfied when
    // T is i32, and coercion to a trait object &Debug works for &i32.
    variable(&s as &i32);
    object(&s as &i32);
}

The call to concrete works just fine, because Rust is trying to coerce a &S to a &i32, so it tries the Deref coercions.

The first call to variable fails, because Rust matches &S with &T, says, "Okay, the type variable T must be S," and then says "S doesn't implement Debug, fail". Since the two concrete types &S and &i32 never get paired up, it never tries to apply Deref coercions.

I believe the first call to object fails for similar reasons: coercion to a trait object &Tr requires a reference of type &T for some T: Tr; again, the constraint isn't satisfied.

That phrasing has been the most helpful way for me to think about it.

1 Like

@jimb That example - and your description - was super helpful. Thank you.

And yes, @DanielKeep's statement below is the most helpful way to think about this.

To put it another way: Rust won't deref something to try and satisfy constraints.

Thanks guys!