Create helper maybe_report_similar_assoc_fn
This commit is contained in:
parent
a4cb55f2ac
commit
0b6af718d8
@ -14,6 +14,7 @@
|
|||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_infer::traits::FulfillmentError;
|
use rustc_infer::traits::FulfillmentError;
|
||||||
|
use rustc_middle::query::Key;
|
||||||
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeVisitableExt};
|
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeVisitableExt};
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_span::edit_distance::find_best_match_for_name;
|
use rustc_span::edit_distance::find_best_match_for_name;
|
||||||
@ -859,6 +860,56 @@ pub(crate) fn complain_about_missing_associated_types(
|
|||||||
|
|
||||||
self.set_tainted_by_errors(err.emit());
|
self.set_tainted_by_errors(err.emit());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// On ambiguous associated type, look for an associated function whose name matches the
|
||||||
|
/// extended path and, if found, emit an E0223 error with a structured suggestion.
|
||||||
|
/// e.g. for `String::from::utf8`, suggest `String::from_utf8` (#109195)
|
||||||
|
pub(crate) fn maybe_report_similar_assoc_fn(
|
||||||
|
&self,
|
||||||
|
span: Span,
|
||||||
|
qself_ty: Ty<'tcx>,
|
||||||
|
qself: &hir::Ty<'_>,
|
||||||
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
|
let tcx = self.tcx();
|
||||||
|
if let Some((_, node)) = tcx.hir().parent_iter(qself.hir_id).skip(1).next()
|
||||||
|
&& let hir::Node::Expr(hir::Expr {
|
||||||
|
kind:
|
||||||
|
hir::ExprKind::Path(hir::QPath::TypeRelative(
|
||||||
|
hir::Ty {
|
||||||
|
kind:
|
||||||
|
hir::TyKind::Path(hir::QPath::TypeRelative(
|
||||||
|
_,
|
||||||
|
hir::PathSegment { ident: ident2, .. },
|
||||||
|
)),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
hir::PathSegment { ident: ident3, .. },
|
||||||
|
)),
|
||||||
|
..
|
||||||
|
}) = node
|
||||||
|
&& let Some(ty_def_id) = qself_ty.ty_def_id()
|
||||||
|
&& let Ok([inherent_impl]) = tcx.inherent_impls(ty_def_id)
|
||||||
|
&& let name = format!("{ident2}_{ident3}")
|
||||||
|
&& let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = tcx
|
||||||
|
.associated_items(inherent_impl)
|
||||||
|
.filter_by_name_unhygienic(Symbol::intern(&name))
|
||||||
|
.next()
|
||||||
|
{
|
||||||
|
let reported =
|
||||||
|
struct_span_code_err!(tcx.dcx(), span, E0223, "ambiguous associated type")
|
||||||
|
.with_span_suggestion_verbose(
|
||||||
|
ident2.span.to(ident3.span),
|
||||||
|
format!("there is an associated function with a similar name: `{name}`"),
|
||||||
|
name,
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
self.set_tainted_by_errors(reported);
|
||||||
|
Err(reported)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emits an error regarding forbidden type binding associations
|
/// Emits an error regarding forbidden type binding associations
|
||||||
|
@ -29,7 +29,6 @@
|
|||||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::ObligationCause;
|
use rustc_infer::traits::ObligationCause;
|
||||||
use rustc_middle::middle::stability::AllowUnstable;
|
use rustc_middle::middle::stability::AllowUnstable;
|
||||||
use rustc_middle::query::Key;
|
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, IsSuggestable, ParamEnv, Ty,
|
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, IsSuggestable, ParamEnv, Ty,
|
||||||
TyCtxt, TypeVisitableExt,
|
TyCtxt, TypeVisitableExt,
|
||||||
@ -1374,56 +1373,7 @@ pub fn associated_path_to_ty(
|
|||||||
)
|
)
|
||||||
.emit() // Already reported in an earlier stage.
|
.emit() // Already reported in an earlier stage.
|
||||||
} else {
|
} else {
|
||||||
// suggest methods that look similar to the path
|
self.maybe_report_similar_assoc_fn(span, qself_ty, qself)?;
|
||||||
// e.g. for `String::from::utf8`, suggest `String::from_utf8` (#109195)
|
|
||||||
for (_, node) in tcx.hir().parent_iter(qself.hir_id) {
|
|
||||||
if let hir::Node::Expr(hir::Expr {
|
|
||||||
kind:
|
|
||||||
hir::ExprKind::Path(hir::QPath::TypeRelative(
|
|
||||||
hir::Ty {
|
|
||||||
kind:
|
|
||||||
hir::TyKind::Path(hir::QPath::TypeRelative(
|
|
||||||
_,
|
|
||||||
hir::PathSegment { ident: ident2, .. },
|
|
||||||
)),
|
|
||||||
..
|
|
||||||
},
|
|
||||||
hir::PathSegment { ident: ident3, .. },
|
|
||||||
)),
|
|
||||||
..
|
|
||||||
}) = node
|
|
||||||
{
|
|
||||||
let name = format!("{ident2}_{ident3}");
|
|
||||||
if if let Some(ty_def_id) = qself_ty.ty_def_id()
|
|
||||||
&& let Ok([inherent_impl]) = tcx.inherent_impls(ty_def_id)
|
|
||||||
&& let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = tcx
|
|
||||||
.associated_items(inherent_impl)
|
|
||||||
.filter_by_name_unhygienic(Symbol::intern(&name))
|
|
||||||
.next()
|
|
||||||
{
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
qself_ty.is_str()
|
|
||||||
&& ["from_utf8", "from_utf8_mut"].contains(&name.as_str())
|
|
||||||
} {
|
|
||||||
let reported = struct_span_code_err!(
|
|
||||||
tcx.dcx(),
|
|
||||||
span,
|
|
||||||
E0223,
|
|
||||||
"ambiguous associated type"
|
|
||||||
)
|
|
||||||
.with_span_suggestion_verbose(
|
|
||||||
ident2.span.to(ident3.span),
|
|
||||||
format!("you might have meant to use `{name}`"),
|
|
||||||
name,
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
self.set_tainted_by_errors(reported);
|
|
||||||
return Err(reported);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let traits: Vec<_> =
|
let traits: Vec<_> =
|
||||||
self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident);
|
self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident);
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
String::from::utf8;
|
String::from::utf8;
|
||||||
//~^ ERROR ambiguous associated type [E0223]
|
//~^ ERROR ambiguous associated type [E0223]
|
||||||
//~| HELP you might have meant to use `from_utf8`
|
//~| HELP there is an associated function with a similar name: `from_utf8`
|
||||||
String::from::utf8();
|
String::from::utf8();
|
||||||
//~^ ERROR ambiguous associated type [E0223]
|
//~^ ERROR ambiguous associated type [E0223]
|
||||||
//~| HELP you might have meant to use `from_utf8`
|
//~| HELP there is an associated function with a similar name: `from_utf8`
|
||||||
String::from::utf16();
|
String::from::utf16();
|
||||||
//~^ ERROR ambiguous associated type [E0223]
|
//~^ ERROR ambiguous associated type [E0223]
|
||||||
//~| HELP you might have meant to use `from_utf16`
|
//~| HELP there is an associated function with a similar name: `from_utf16`
|
||||||
String::from::method_that_doesnt_exist();
|
String::from::method_that_doesnt_exist();
|
||||||
//~^ ERROR ambiguous associated type [E0223]
|
//~^ ERROR ambiguous associated type [E0223]
|
||||||
//~| HELP if there were a trait named `Example` with associated type `from`
|
//~| HELP if there were a trait named `Example` with associated type `from`
|
||||||
str::from::utf8();
|
str::from::utf8();
|
||||||
//~^ ERROR ambiguous associated type [E0223]
|
//~^ ERROR ambiguous associated type [E0223]
|
||||||
//~| HELP you might have meant to use `from_utf8`
|
//~| HELP if there were a trait named `Example` with associated type `from`
|
||||||
str::from::utf8_mut();
|
str::from::utf8_mut();
|
||||||
//~^ ERROR ambiguous associated type [E0223]
|
//~^ ERROR ambiguous associated type [E0223]
|
||||||
//~| HELP you might have meant to use `from_utf8_mut`
|
//~| HELP if there were a trait named `Example` with associated type `from`
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ error[E0223]: ambiguous associated type
|
|||||||
LL | String::from::utf8;
|
LL | String::from::utf8;
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: you might have meant to use `from_utf8`
|
help: there is an associated function with a similar name: `from_utf8`
|
||||||
|
|
|
|
||||||
LL | String::from_utf8;
|
LL | String::from_utf8;
|
||||||
| ~~~~~~~~~
|
| ~~~~~~~~~
|
||||||
@ -15,7 +15,7 @@ error[E0223]: ambiguous associated type
|
|||||||
LL | String::from::utf8();
|
LL | String::from::utf8();
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: you might have meant to use `from_utf8`
|
help: there is an associated function with a similar name: `from_utf8`
|
||||||
|
|
|
|
||||||
LL | String::from_utf8();
|
LL | String::from_utf8();
|
||||||
| ~~~~~~~~~
|
| ~~~~~~~~~
|
||||||
@ -26,7 +26,7 @@ error[E0223]: ambiguous associated type
|
|||||||
LL | String::from::utf16();
|
LL | String::from::utf16();
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: you might have meant to use `from_utf16`
|
help: there is an associated function with a similar name: `from_utf16`
|
||||||
|
|
|
|
||||||
LL | String::from_utf16();
|
LL | String::from_utf16();
|
||||||
| ~~~~~~~~~~
|
| ~~~~~~~~~~
|
||||||
@ -48,10 +48,10 @@ error[E0223]: ambiguous associated type
|
|||||||
LL | str::from::utf8();
|
LL | str::from::utf8();
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: you might have meant to use `from_utf8`
|
help: if there were a trait named `Example` with associated type `from` implemented for `str`, you could use the fully-qualified path
|
||||||
|
|
|
|
||||||
LL | str::from_utf8();
|
LL | <str as Example>::from::utf8();
|
||||||
| ~~~~~~~~~
|
| ~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
error[E0223]: ambiguous associated type
|
error[E0223]: ambiguous associated type
|
||||||
--> $DIR/issue-109195.rs:17:5
|
--> $DIR/issue-109195.rs:17:5
|
||||||
@ -59,10 +59,10 @@ error[E0223]: ambiguous associated type
|
|||||||
LL | str::from::utf8_mut();
|
LL | str::from::utf8_mut();
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: you might have meant to use `from_utf8_mut`
|
help: if there were a trait named `Example` with associated type `from` implemented for `str`, you could use the fully-qualified path
|
||||||
|
|
|
|
||||||
LL | str::from_utf8_mut();
|
LL | <str as Example>::from::utf8_mut();
|
||||||
| ~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
error: aborting due to 6 previous errors
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user