2

While reading How can I reborrow a mutable reference without passing it to a function?, the OP had a function like:

fn deref<'a, 'b: 'a, T>(t: &'a mut &'b mut T) -> &'a mut T {
    *t
}

This makes sense to me. However, they also pointed out that the explicit dereference in the body * wasn't required:

fn deref<'a, 'b: 'a, T>(t: &'a mut &'b mut T) -> &'a mut T {
    t
}

This compiles, and I don't know why. I'm familiar with automatic dereferencing, but I was under the impression that only came into play with function arguments, not return values.

Community
  • 1
  • 1
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366

1 Answers1

3

Reading the relevant docs, it seems that the Deref conversion always happens as many times as it needs to - wherever it needs to. The only really funky additional trick that Deref pulls is that it also works magic on self arguments.

The following snippets both work - and the expressions here are definitely not constrained to be arguments or return values.

// &&&&1 gets dereferenced to &i32 from &&&&i32
let x: &i32 = &&&&1;
let x: (&i32,) = (&&&&1,);

The only gotcha with this sort of thing that remains is that Deref only applies to types of the form &U, so something like &1 can never be coerced to &i32 from i32, even if &&1 can be coerced from &&i32 to &i32.


As a side note, I realize that type ascriptions are a bit special, but it seems Deref doesn't do conversions there. I'm not sure if it is by design or not, or if I'm just misunderstanding something. The following doesn't work.

#![feature(type_ascription)]

// ....

let x = &&1i32: &i32;

Based on this comment (and the very relevant thread from which it originates), it looks like this is just a type ascription issue. It appears that for now, type ascription is implemented without coercions, but almost everyone agrees that that should not be the case (in fact, one of the good use cases of type ascriptions would be to hint to the compiler which coercions to apply).

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Alec
  • 31,829
  • 7
  • 67
  • 114
  • I guess my problem stems from the fact that while nothing ever says it's restricted to function arguments, that's how it's always demonstrated (even in the docs you linked to). My brain must have fused the two concepts together. Thinking back on it, I even **use** deref coercions in my own code: `struct Foo(String); impl Foo { fn name(&self) -> &str { &self.0 } }`. – Shepmaster Mar 27 '17 at 01:33
  • @Shepmaster Are you seeing what I'm missing for type ascriptions though? It's bugging me a bit because my mental model of type checking around `let x: T = y;` has been `let x = y: T;`.... – Alec Mar 27 '17 at 01:36
  • Skimming through the [ascription RFC](https://github.com/rust-lang/rfcs/blob/master/text/0803-type-ascription.md), I don't see anything obvious. The "Type ascription and temporaries" section *might* be relevant though. The [tracking issue](https://github.com/rust-lang/rust/issues/23416) also does not have any obvious mention of `Deref`. Could be worth adding a comment on that issue to see if it's deliberate or not. – Shepmaster Mar 27 '17 at 01:46
  • @Shepmaster Looks like it is an ongoing issue. See my edit. – Alec Mar 27 '17 at 01:59
  • A [more recent comment about type ascription and coercion](https://github.com/rust-lang/rust/issues/23416#issuecomment-315785799) indicates that there are some soundness issues. – Shepmaster Jul 17 '17 at 17:22