ref is not related to Deref. The deref coercion is automatically inserted to some places but doesn't affect the matched variables directly.
If type T is matched to ref x then type of x is &T. But then why not just match for x and use &x? Consider this code:
#[derive(Debug)]
struct S;
fn use_s(_: &S) {}
let x: Option<S> = Some(S);
if let Some(ref y) = x {
/* y : &S */
use_s(y);
}
dbg!(x);
If I remove ref,
if let Some(y) = x {
/* y : S */
use_s(&y);
}
dbg!(x);
It doesn't compile. The error tells use x is moved by the pattern matching but later used.
It is similar to that "&some_struct.field" doesn't move some_struct out.
Technically, pattern matching matches against "place" instead of "value" (if you are familiar with C++, you can read "place" as "lvalue").
Today, the ref pattern is almost superseded by the "match ergonomics" which automatically insert & pattern and ref pattern to appropriate places.
The Option example can be written as:
let msg: Option<&str> = Some("howdy");
if let Some(m) = &msg { /* m : &&str */ }