diff --git a/clippy_lints/src/matches/match_as_ref.rs b/clippy_lints/src/matches/match_as_ref.rs index 2c4d08639f61..b375073567a0 100644 --- a/clippy_lints/src/matches/match_as_ref.rs +++ b/clippy_lints/src/matches/match_as_ref.rs @@ -21,20 +21,35 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: } else { None } + && let output_ty = cx.typeck_results().expr_ty(expr) + && let input_ty = cx.typeck_results().expr_ty(ex) + && let Some(input_ty) = option_arg_ty(cx, input_ty) + && let Some(output_ty) = option_arg_ty(cx, output_ty) + && let ty::Ref(_, output_ty, output_mutbl) = *output_ty.kind() { let method = match arm_ref_mutbl { Mutability::Not => "as_ref", Mutability::Mut => "as_mut", }; - let output_ty = cx.typeck_results().expr_ty(expr); - let input_ty = cx.typeck_results().expr_ty(ex); - - let cast = if let Some(input_ty) = option_arg_ty(cx, input_ty) - && let Some(output_ty) = option_arg_ty(cx, output_ty) - && let ty::Ref(_, output_ty, _) = *output_ty.kind() - && input_ty != output_ty - { + let cast = if arm_ref_mutbl != output_mutbl || input_ty != output_ty { + // We'll need to downcast either the type (`&i32 as &dyn std::fmt::Debug`): + // ``` + // let _: Option<&dyn std::fmt::Debug> = match 0i32 { + // Some(ref t) => Some(t), + // None => None, + // }; + // ``` + // or the reference (`&mut i32 as &i32`) + // ``` + // let _: Option<&i32> = match 0i32 { + // Some(ref mut t) => Some(t), + // None => None, + // }; + // ``` + // or both. + // + // `.map` will take care of all of it. ".map(|x| x as _)" } else { "" diff --git a/tests/ui/match_as_ref.fixed b/tests/ui/match_as_ref.fixed index 3653b81eda22..b3e97e1889bf 100644 --- a/tests/ui/match_as_ref.fixed +++ b/tests/ui/match_as_ref.fixed @@ -84,3 +84,9 @@ fn recv_requiring_parens() { let _ = (!S).as_ref(); } + +fn issue15932() { + let _: Option<&i32> = Some(0).as_mut().map(|x| x as _); + + let _: Option<&dyn std::fmt::Debug> = Some(0).as_mut().map(|x| x as _); +} diff --git a/tests/ui/match_as_ref.rs b/tests/ui/match_as_ref.rs index d58cfd81aeab..7cabdc6a93cb 100644 --- a/tests/ui/match_as_ref.rs +++ b/tests/ui/match_as_ref.rs @@ -100,3 +100,17 @@ fn recv_requiring_parens() { Some(ref v) => Some(v), }; } + +fn issue15932() { + let _: Option<&i32> = match Some(0) { + //~^ match_as_ref + None => None, + Some(ref mut v) => Some(v), + }; + + let _: Option<&dyn std::fmt::Debug> = match Some(0) { + //~^ match_as_ref + None => None, + Some(ref mut v) => Some(v), + }; +} diff --git a/tests/ui/match_as_ref.stderr b/tests/ui/match_as_ref.stderr index 226655970ab8..47eeb449a9cd 100644 --- a/tests/ui/match_as_ref.stderr +++ b/tests/ui/match_as_ref.stderr @@ -83,5 +83,47 @@ LL - }; LL + let _ = (!S).as_ref(); | -error: aborting due to 4 previous errors +error: manual implementation of `Option::as_mut` + --> tests/ui/match_as_ref.rs:105:27 + | +LL | let _: Option<&i32> = match Some(0) { + | ___________________________^ +LL | | +LL | | None => None, +LL | | Some(ref mut v) => Some(v), +LL | | }; + | |_____^ + | +help: use `Option::as_mut()` directly + | +LL - let _: Option<&i32> = match Some(0) { +LL - +LL - None => None, +LL - Some(ref mut v) => Some(v), +LL - }; +LL + let _: Option<&i32> = Some(0).as_mut().map(|x| x as _); + | + +error: manual implementation of `Option::as_mut` + --> tests/ui/match_as_ref.rs:111:43 + | +LL | let _: Option<&dyn std::fmt::Debug> = match Some(0) { + | ___________________________________________^ +LL | | +LL | | None => None, +LL | | Some(ref mut v) => Some(v), +LL | | }; + | |_____^ + | +help: use `Option::as_mut()` directly + | +LL - let _: Option<&dyn std::fmt::Debug> = match Some(0) { +LL - +LL - None => None, +LL - Some(ref mut v) => Some(v), +LL - }; +LL + let _: Option<&dyn std::fmt::Debug> = Some(0).as_mut().map(|x| x as _); + | + +error: aborting due to 6 previous errors