Skip to content

Commit 0b6af71

Browse files
committed
Create helper maybe_report_similar_assoc_fn
1 parent a4cb55f commit 0b6af71

File tree

4 files changed

+66
-65
lines changed

4 files changed

+66
-65
lines changed

compiler/rustc_hir_analysis/src/astconv/errors.rs

+51
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use rustc_errors::{
1414
use rustc_hir as hir;
1515
use rustc_hir::def_id::{DefId, LocalDefId};
1616
use rustc_infer::traits::FulfillmentError;
17+
use rustc_middle::query::Key;
1718
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeVisitableExt};
1819
use rustc_session::parse::feature_err;
1920
use rustc_span::edit_distance::find_best_match_for_name;
@@ -859,6 +860,56 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
859860

860861
self.set_tainted_by_errors(err.emit());
861862
}
863+
864+
/// On ambiguous associated type, look for an associated function whose name matches the
865+
/// extended path and, if found, emit an E0223 error with a structured suggestion.
866+
/// e.g. for `String::from::utf8`, suggest `String::from_utf8` (#109195)
867+
pub(crate) fn maybe_report_similar_assoc_fn(
868+
&self,
869+
span: Span,
870+
qself_ty: Ty<'tcx>,
871+
qself: &hir::Ty<'_>,
872+
) -> Result<(), ErrorGuaranteed> {
873+
let tcx = self.tcx();
874+
if let Some((_, node)) = tcx.hir().parent_iter(qself.hir_id).skip(1).next()
875+
&& let hir::Node::Expr(hir::Expr {
876+
kind:
877+
hir::ExprKind::Path(hir::QPath::TypeRelative(
878+
hir::Ty {
879+
kind:
880+
hir::TyKind::Path(hir::QPath::TypeRelative(
881+
_,
882+
hir::PathSegment { ident: ident2, .. },
883+
)),
884+
..
885+
},
886+
hir::PathSegment { ident: ident3, .. },
887+
)),
888+
..
889+
}) = node
890+
&& let Some(ty_def_id) = qself_ty.ty_def_id()
891+
&& let Ok([inherent_impl]) = tcx.inherent_impls(ty_def_id)
892+
&& let name = format!("{ident2}_{ident3}")
893+
&& let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = tcx
894+
.associated_items(inherent_impl)
895+
.filter_by_name_unhygienic(Symbol::intern(&name))
896+
.next()
897+
{
898+
let reported =
899+
struct_span_code_err!(tcx.dcx(), span, E0223, "ambiguous associated type")
900+
.with_span_suggestion_verbose(
901+
ident2.span.to(ident3.span),
902+
format!("there is an associated function with a similar name: `{name}`"),
903+
name,
904+
Applicability::MaybeIncorrect,
905+
)
906+
.emit();
907+
self.set_tainted_by_errors(reported);
908+
Err(reported)
909+
} else {
910+
Ok(())
911+
}
912+
}
862913
}
863914

864915
/// Emits an error regarding forbidden type binding associations

compiler/rustc_hir_analysis/src/astconv/mod.rs

+1-51
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
2929
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
3030
use rustc_infer::traits::ObligationCause;
3131
use rustc_middle::middle::stability::AllowUnstable;
32-
use rustc_middle::query::Key;
3332
use rustc_middle::ty::{
3433
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, IsSuggestable, ParamEnv, Ty,
3534
TyCtxt, TypeVisitableExt,
@@ -1374,56 +1373,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
13741373
)
13751374
.emit() // Already reported in an earlier stage.
13761375
} else {
1377-
// suggest methods that look similar to the path
1378-
// e.g. for `String::from::utf8`, suggest `String::from_utf8` (#109195)
1379-
for (_, node) in tcx.hir().parent_iter(qself.hir_id) {
1380-
if let hir::Node::Expr(hir::Expr {
1381-
kind:
1382-
hir::ExprKind::Path(hir::QPath::TypeRelative(
1383-
hir::Ty {
1384-
kind:
1385-
hir::TyKind::Path(hir::QPath::TypeRelative(
1386-
_,
1387-
hir::PathSegment { ident: ident2, .. },
1388-
)),
1389-
..
1390-
},
1391-
hir::PathSegment { ident: ident3, .. },
1392-
)),
1393-
..
1394-
}) = node
1395-
{
1396-
let name = format!("{ident2}_{ident3}");
1397-
if if let Some(ty_def_id) = qself_ty.ty_def_id()
1398-
&& let Ok([inherent_impl]) = tcx.inherent_impls(ty_def_id)
1399-
&& let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = tcx
1400-
.associated_items(inherent_impl)
1401-
.filter_by_name_unhygienic(Symbol::intern(&name))
1402-
.next()
1403-
{
1404-
true
1405-
} else {
1406-
qself_ty.is_str()
1407-
&& ["from_utf8", "from_utf8_mut"].contains(&name.as_str())
1408-
} {
1409-
let reported = struct_span_code_err!(
1410-
tcx.dcx(),
1411-
span,
1412-
E0223,
1413-
"ambiguous associated type"
1414-
)
1415-
.with_span_suggestion_verbose(
1416-
ident2.span.to(ident3.span),
1417-
format!("you might have meant to use `{name}`"),
1418-
name,
1419-
Applicability::MaybeIncorrect,
1420-
)
1421-
.emit();
1422-
self.set_tainted_by_errors(reported);
1423-
return Err(reported);
1424-
}
1425-
}
1426-
}
1376+
self.maybe_report_similar_assoc_fn(span, qself_ty, qself)?;
14271377

14281378
let traits: Vec<_> =
14291379
self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident);

tests/ui/suggestions/issue-109195.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
fn main() {
22
String::from::utf8;
33
//~^ ERROR ambiguous associated type [E0223]
4-
//~| HELP you might have meant to use `from_utf8`
4+
//~| HELP there is an associated function with a similar name: `from_utf8`
55
String::from::utf8();
66
//~^ ERROR ambiguous associated type [E0223]
7-
//~| HELP you might have meant to use `from_utf8`
7+
//~| HELP there is an associated function with a similar name: `from_utf8`
88
String::from::utf16();
99
//~^ ERROR ambiguous associated type [E0223]
10-
//~| HELP you might have meant to use `from_utf16`
10+
//~| HELP there is an associated function with a similar name: `from_utf16`
1111
String::from::method_that_doesnt_exist();
1212
//~^ ERROR ambiguous associated type [E0223]
1313
//~| HELP if there were a trait named `Example` with associated type `from`
1414
str::from::utf8();
1515
//~^ ERROR ambiguous associated type [E0223]
16-
//~| HELP you might have meant to use `from_utf8`
16+
//~| HELP if there were a trait named `Example` with associated type `from`
1717
str::from::utf8_mut();
1818
//~^ ERROR ambiguous associated type [E0223]
19-
//~| HELP you might have meant to use `from_utf8_mut`
19+
//~| HELP if there were a trait named `Example` with associated type `from`
2020
}

tests/ui/suggestions/issue-109195.stderr

+9-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error[E0223]: ambiguous associated type
44
LL | String::from::utf8;
55
| ^^^^^^^^^^^^
66
|
7-
help: you might have meant to use `from_utf8`
7+
help: there is an associated function with a similar name: `from_utf8`
88
|
99
LL | String::from_utf8;
1010
| ~~~~~~~~~
@@ -15,7 +15,7 @@ error[E0223]: ambiguous associated type
1515
LL | String::from::utf8();
1616
| ^^^^^^^^^^^^
1717
|
18-
help: you might have meant to use `from_utf8`
18+
help: there is an associated function with a similar name: `from_utf8`
1919
|
2020
LL | String::from_utf8();
2121
| ~~~~~~~~~
@@ -26,7 +26,7 @@ error[E0223]: ambiguous associated type
2626
LL | String::from::utf16();
2727
| ^^^^^^^^^^^^
2828
|
29-
help: you might have meant to use `from_utf16`
29+
help: there is an associated function with a similar name: `from_utf16`
3030
|
3131
LL | String::from_utf16();
3232
| ~~~~~~~~~~
@@ -48,21 +48,21 @@ error[E0223]: ambiguous associated type
4848
LL | str::from::utf8();
4949
| ^^^^^^^^^
5050
|
51-
help: you might have meant to use `from_utf8`
51+
help: if there were a trait named `Example` with associated type `from` implemented for `str`, you could use the fully-qualified path
5252
|
53-
LL | str::from_utf8();
54-
| ~~~~~~~~~
53+
LL | <str as Example>::from::utf8();
54+
| ~~~~~~~~~~~~~~~~~~~~~~
5555

5656
error[E0223]: ambiguous associated type
5757
--> $DIR/issue-109195.rs:17:5
5858
|
5959
LL | str::from::utf8_mut();
6060
| ^^^^^^^^^
6161
|
62-
help: you might have meant to use `from_utf8_mut`
62+
help: if there were a trait named `Example` with associated type `from` implemented for `str`, you could use the fully-qualified path
6363
|
64-
LL | str::from_utf8_mut();
65-
| ~~~~~~~~~~~~~
64+
LL | <str as Example>::from::utf8_mut();
65+
| ~~~~~~~~~~~~~~~~~~~~~~
6666

6767
error: aborting due to 6 previous errors
6868

0 commit comments

Comments
 (0)