Skip to content

Commit b7a1ff2

Browse files
authored
Rollup merge of #114052 - clubby789:suggest-option-asref, r=WaffleLapkin
Suggest `{Option,Result}::as_ref()` instead of `cloned()` in some cases Fixes #114050 When we have an expr available that produces the type expectation, we can suggest appending `.as_ref()` to the span, instead of cloning the expr producing the mismatch
2 parents 99f404a + c83dfe9 commit b7a1ff2

8 files changed

+67
-8
lines changed

compiler/rustc_hir_typeck/src/demand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
5353
|| self.suggest_no_capture_closure(err, expected, expr_ty)
5454
|| self.suggest_boxing_when_appropriate(err, expr.span, expr.hir_id, expected, expr_ty)
5555
|| self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
56-
|| self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
56+
|| self.suggest_copied_cloned_or_as_ref(err, expr, expr_ty, expected, expected_ty_expr)
5757
|| self.suggest_clone_for_ref(err, expr, expr_ty, expected)
5858
|| self.suggest_into(err, expr, expr_ty, expected)
5959
|| self.suggest_floating_point_literal(err, expr, expected)

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+15-4
Original file line numberDiff line numberDiff line change
@@ -1085,12 +1085,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10851085
false
10861086
}
10871087

1088-
pub(crate) fn suggest_copied_or_cloned(
1088+
pub(crate) fn suggest_copied_cloned_or_as_ref(
10891089
&self,
10901090
diag: &mut Diagnostic,
10911091
expr: &hir::Expr<'_>,
10921092
expr_ty: Ty<'tcx>,
10931093
expected_ty: Ty<'tcx>,
1094+
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
10941095
) -> bool {
10951096
let ty::Adt(adt_def, args) = expr_ty.kind() else {
10961097
return false;
@@ -1102,7 +1103,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11021103
return false;
11031104
}
11041105

1105-
let mut suggest_copied_or_cloned = || {
1106+
let mut suggest_copied_cloned_or_as_ref = || {
11061107
let expr_inner_ty = args.type_at(0);
11071108
let expected_inner_ty = expected_args.type_at(0);
11081109
if let &ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind()
@@ -1119,6 +1120,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11191120
Applicability::MachineApplicable,
11201121
);
11211122
return true;
1123+
} else if let Some(expected_ty_expr) = expected_ty_expr {
1124+
diag.span_suggestion_verbose(
1125+
expected_ty_expr.span.shrink_to_hi(),
1126+
format!(
1127+
"use `{def_path}::as_ref()` to convert `{expected_ty}` to `{expr_ty}`"
1128+
),
1129+
".as_ref()",
1130+
Applicability::MachineApplicable,
1131+
);
1132+
return true;
11221133
} else if let Some(clone_did) = self.tcx.lang_items().clone_trait()
11231134
&& rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions(
11241135
self,
@@ -1146,11 +1157,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11461157
// Check that the error types are equal
11471158
&& self.can_eq(self.param_env, args.type_at(1), expected_args.type_at(1))
11481159
{
1149-
return suggest_copied_or_cloned();
1160+
return suggest_copied_cloned_or_as_ref();
11501161
} else if let Some(option_did) = self.tcx.get_diagnostic_item(sym::Option)
11511162
&& adt_def.did() == option_did
11521163
{
1153-
return suggest_copied_or_cloned();
1164+
return suggest_copied_cloned_or_as_ref();
11541165
}
11551166

11561167
false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// run-rustfix
2+
3+
use std::fmt::Debug;
4+
5+
pub fn foo<I: Iterator>(mut iter: I, value: &I::Item)
6+
where
7+
I::Item: Eq + Debug,
8+
{
9+
debug_assert_eq!(iter.next().as_ref(), Some(value));
10+
//~^ ERROR mismatched types
11+
}
12+
13+
fn main() {}

tests/ui/associated-types/dont-suggest-cyclic-constraint.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
// run-rustfix
2+
13
use std::fmt::Debug;
24

3-
fn foo<I: Iterator>(mut iter: I, value: &I::Item)
5+
pub fn foo<I: Iterator>(mut iter: I, value: &I::Item)
46
where
57
I::Item: Eq + Debug,
68
{

tests/ui/associated-types/dont-suggest-cyclic-constraint.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
error[E0308]: mismatched types
2-
--> $DIR/dont-suggest-cyclic-constraint.rs:7:35
2+
--> $DIR/dont-suggest-cyclic-constraint.rs:9:35
33
|
44
LL | debug_assert_eq!(iter.next(), Some(value));
55
| ^^^^^^^^^^^ expected `Option<<I as Iterator>::Item>`, found `Option<&<I as Iterator>::Item>`
66
|
77
= note: expected enum `Option<<I as Iterator>::Item>`
88
found enum `Option<&<I as Iterator>::Item>`
9+
help: use `Option::as_ref()` to convert `Option<<I as Iterator>::Item>` to `Option<&<I as Iterator>::Item>`
10+
|
11+
LL | debug_assert_eq!(iter.next().as_ref(), Some(value));
12+
| +++++++++
913

1014
error: aborting due to previous error
1115

tests/ui/suggestions/copied-and-cloned.fixed

+8
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,12 @@ fn main() {
2020
expect::<Result<String, ()>>(x.cloned());
2121
//~^ ERROR mismatched types
2222
//~| HELP use `Result::cloned` to clone the value inside the `Result`
23+
24+
let s = String::new();
25+
let x = Some(s.clone());
26+
let y = Some(&s);
27+
println!("{}", x.as_ref() == y);
28+
//~^ ERROR mismatched types
29+
//~| HELP use `Option::as_ref()` to convert `Option<String>` to `Option<&String>`
30+
2331
}

tests/ui/suggestions/copied-and-cloned.rs

+8
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,12 @@ fn main() {
2020
expect::<Result<String, ()>>(x);
2121
//~^ ERROR mismatched types
2222
//~| HELP use `Result::cloned` to clone the value inside the `Result`
23+
24+
let s = String::new();
25+
let x = Some(s.clone());
26+
let y = Some(&s);
27+
println!("{}", x == y);
28+
//~^ ERROR mismatched types
29+
//~| HELP use `Option::as_ref()` to convert `Option<String>` to `Option<&String>`
30+
2331
}

tests/ui/suggestions/copied-and-cloned.stderr

+14-1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,19 @@ help: use `Result::cloned` to clone the value inside the `Result`
7878
LL | expect::<Result<String, ()>>(x.cloned());
7979
| +++++++++
8080

81-
error: aborting due to 4 previous errors
81+
error[E0308]: mismatched types
82+
--> $DIR/copied-and-cloned.rs:27:25
83+
|
84+
LL | println!("{}", x == y);
85+
| ^ expected `Option<String>`, found `Option<&String>`
86+
|
87+
= note: expected enum `Option<String>`
88+
found enum `Option<&String>`
89+
help: use `Option::as_ref()` to convert `Option<String>` to `Option<&String>`
90+
|
91+
LL | println!("{}", x.as_ref() == y);
92+
| +++++++++
93+
94+
error: aborting due to 5 previous errors
8295

8396
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)