Rollup merge of #117655 - compiler-errors:method-tweaks, r=estebank
Method suggestion code tweaks I was rummaging around the method suggestion code after https://github.com/rust-lang/rust/pull/117006#discussion_r1384153722 and saw a few things to simplify. This is two unrelated commits, both in the same file. Review them separately, if you'd like. r? estebank
This commit is contained in:
commit
f72e974e3f
12 changed files with 178 additions and 198 deletions
|
@ -13,7 +13,7 @@ use crate::errors::{
|
||||||
YieldExprOutsideOfCoroutine,
|
YieldExprOutsideOfCoroutine,
|
||||||
};
|
};
|
||||||
use crate::fatally_break_rust;
|
use crate::fatally_break_rust;
|
||||||
use crate::method::{MethodCallComponents, SelfSource};
|
use crate::method::SelfSource;
|
||||||
use crate::type_error_struct;
|
use crate::type_error_struct;
|
||||||
use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
|
use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -512,7 +512,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let (res, opt_ty, segs) =
|
let (res, opt_ty, segs) =
|
||||||
self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span);
|
self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span, Some(args));
|
||||||
let ty = match res {
|
let ty = match res {
|
||||||
Res::Err => {
|
Res::Err => {
|
||||||
self.suggest_assoc_method_call(segs);
|
self.suggest_assoc_method_call(segs);
|
||||||
|
@ -1332,7 +1332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
segment.ident,
|
segment.ident,
|
||||||
SelfSource::MethodCall(rcvr),
|
SelfSource::MethodCall(rcvr),
|
||||||
error,
|
error,
|
||||||
Some(MethodCallComponents { receiver: rcvr, args, full_expr: expr }),
|
Some(args),
|
||||||
expected,
|
expected,
|
||||||
false,
|
false,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -797,6 +797,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
qpath: &'tcx QPath<'tcx>,
|
qpath: &'tcx QPath<'tcx>,
|
||||||
hir_id: hir::HirId,
|
hir_id: hir::HirId,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
args: Option<&'tcx [hir::Expr<'tcx>]>,
|
||||||
) -> (Res, Option<RawTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]) {
|
) -> (Res, Option<RawTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]) {
|
||||||
debug!(
|
debug!(
|
||||||
"resolve_ty_and_res_fully_qualified_call: qpath={:?} hir_id={:?} span={:?}",
|
"resolve_ty_and_res_fully_qualified_call: qpath={:?} hir_id={:?} span={:?}",
|
||||||
|
@ -898,7 +899,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
item_name,
|
item_name,
|
||||||
SelfSource::QPath(qself),
|
SelfSource::QPath(qself),
|
||||||
error,
|
error,
|
||||||
None,
|
args,
|
||||||
Expectation::NoExpectation,
|
Expectation::NoExpectation,
|
||||||
trait_missing_method && span.edition().at_least_rust_2021(), // emits missing method for trait only after edition 2021
|
trait_missing_method && span.edition().at_least_rust_2021(), // emits missing method for trait only after edition 2021
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -7,7 +7,7 @@ mod prelude2021;
|
||||||
pub mod probe;
|
pub mod probe;
|
||||||
mod suggest;
|
mod suggest;
|
||||||
|
|
||||||
pub use self::suggest::{MethodCallComponents, SelfSource};
|
pub use self::suggest::SelfSource;
|
||||||
pub use self::MethodError::*;
|
pub use self::MethodError::*;
|
||||||
|
|
||||||
use crate::errors::OpMethodGenericParams;
|
use crate::errors::OpMethodGenericParams;
|
||||||
|
|
|
@ -34,7 +34,7 @@ use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
|
||||||
use rustc_span::def_id::DefIdSet;
|
use rustc_span::def_id::DefIdSet;
|
||||||
use rustc_span::symbol::{kw, sym, Ident};
|
use rustc_span::symbol::{kw, sym, Ident};
|
||||||
use rustc_span::Symbol;
|
use rustc_span::Symbol;
|
||||||
use rustc_span::{edit_distance, source_map, ExpnKind, FileName, MacroKind, Span};
|
use rustc_span::{edit_distance, ExpnKind, FileName, MacroKind, Span};
|
||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedNote;
|
use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedNote;
|
||||||
use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _;
|
use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _;
|
||||||
|
@ -50,15 +50,6 @@ use rustc_hir::intravisit::Visitor;
|
||||||
use std::cmp::{self, Ordering};
|
use std::cmp::{self, Ordering};
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
/// After identifying that `full_expr` is a method call, we use this type to keep the expression's
|
|
||||||
/// components readily available to us to point at the right place in diagnostics.
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct MethodCallComponents<'tcx> {
|
|
||||||
pub receiver: &'tcx hir::Expr<'tcx>,
|
|
||||||
pub args: &'tcx [hir::Expr<'tcx>],
|
|
||||||
pub full_expr: &'tcx hir::Expr<'tcx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
@ -124,7 +115,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
item_name: Ident,
|
item_name: Ident,
|
||||||
source: SelfSource<'tcx>,
|
source: SelfSource<'tcx>,
|
||||||
error: MethodError<'tcx>,
|
error: MethodError<'tcx>,
|
||||||
args: Option<MethodCallComponents<'tcx>>,
|
args: Option<&'tcx [hir::Expr<'tcx>]>,
|
||||||
expected: Expectation<'tcx>,
|
expected: Expectation<'tcx>,
|
||||||
trait_missing_method: bool,
|
trait_missing_method: bool,
|
||||||
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
|
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
|
||||||
|
@ -167,6 +158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.note_candidates_on_method_error(
|
self.note_candidates_on_method_error(
|
||||||
rcvr_ty,
|
rcvr_ty,
|
||||||
item_name,
|
item_name,
|
||||||
|
source,
|
||||||
args,
|
args,
|
||||||
span,
|
span,
|
||||||
&mut err,
|
&mut err,
|
||||||
|
@ -266,23 +258,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
fn suggest_missing_writer(
|
fn suggest_missing_writer(
|
||||||
&self,
|
&self,
|
||||||
rcvr_ty: Ty<'tcx>,
|
rcvr_ty: Ty<'tcx>,
|
||||||
args: MethodCallComponents<'tcx>,
|
rcvr_expr: &hir::Expr<'tcx>,
|
||||||
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
|
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
|
||||||
let (ty_str, _ty_file) = self.tcx.short_ty_string(rcvr_ty);
|
let (ty_str, _ty_file) = self.tcx.short_ty_string(rcvr_ty);
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self.tcx.sess,
|
self.tcx.sess,
|
||||||
args.receiver.span,
|
rcvr_expr.span,
|
||||||
E0599,
|
E0599,
|
||||||
"cannot write into `{}`",
|
"cannot write into `{}`",
|
||||||
ty_str
|
ty_str
|
||||||
);
|
);
|
||||||
err.span_note(
|
err.span_note(
|
||||||
args.receiver.span,
|
rcvr_expr.span,
|
||||||
"must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method",
|
"must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method",
|
||||||
);
|
);
|
||||||
if let ExprKind::Lit(_) = args.receiver.kind {
|
if let ExprKind::Lit(_) = rcvr_expr.kind {
|
||||||
err.span_help(
|
err.span_help(
|
||||||
args.receiver.span.shrink_to_lo(),
|
rcvr_expr.span.shrink_to_lo(),
|
||||||
"a writer is needed before this format string",
|
"a writer is needed before this format string",
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -296,7 +288,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
rcvr_ty: Ty<'tcx>,
|
rcvr_ty: Ty<'tcx>,
|
||||||
item_name: Ident,
|
item_name: Ident,
|
||||||
source: SelfSource<'tcx>,
|
source: SelfSource<'tcx>,
|
||||||
args: Option<MethodCallComponents<'tcx>>,
|
args: Option<&'tcx [hir::Expr<'tcx>]>,
|
||||||
sugg_span: Span,
|
sugg_span: Span,
|
||||||
no_match_data: &mut NoMatchData<'tcx>,
|
no_match_data: &mut NoMatchData<'tcx>,
|
||||||
expected: Expectation<'tcx>,
|
expected: Expectation<'tcx>,
|
||||||
|
@ -377,8 +369,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
tcx.is_diagnostic_item(sym::write_macro, def_id)
|
tcx.is_diagnostic_item(sym::write_macro, def_id)
|
||||||
|| tcx.is_diagnostic_item(sym::writeln_macro, def_id)
|
|| tcx.is_diagnostic_item(sym::writeln_macro, def_id)
|
||||||
}) && item_name.name == Symbol::intern("write_fmt");
|
}) && item_name.name == Symbol::intern("write_fmt");
|
||||||
let mut err = if is_write && let Some(args) = args {
|
let mut err =
|
||||||
self.suggest_missing_writer(rcvr_ty, args)
|
if is_write && let SelfSource::MethodCall(rcvr_expr) = source
|
||||||
|
{
|
||||||
|
self.suggest_missing_writer(rcvr_ty, rcvr_expr)
|
||||||
} else {
|
} else {
|
||||||
tcx.sess.create_err(NoAssociatedItem {
|
tcx.sess.create_err(NoAssociatedItem {
|
||||||
span,
|
span,
|
||||||
|
@ -409,7 +403,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
err.downgrade_to_delayed_bug();
|
err.downgrade_to_delayed_bug();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.find_builder_fn(&mut err, rcvr_ty, source);
|
if matches!(source, SelfSource::QPath(_)) && args.is_some() {
|
||||||
|
self.find_builder_fn(&mut err, rcvr_ty);
|
||||||
|
}
|
||||||
|
|
||||||
if tcx.ty_is_opaque_future(rcvr_ty) && item_name.name == sym::poll {
|
if tcx.ty_is_opaque_future(rcvr_ty) && item_name.name == sym::poll {
|
||||||
err.help(format!(
|
err.help(format!(
|
||||||
"method `poll` found on `Pin<&mut {ty_str}>`, \
|
"method `poll` found on `Pin<&mut {ty_str}>`, \
|
||||||
|
@ -523,6 +520,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.note_candidates_on_method_error(
|
self.note_candidates_on_method_error(
|
||||||
rcvr_ty,
|
rcvr_ty,
|
||||||
item_name,
|
item_name,
|
||||||
|
source,
|
||||||
args,
|
args,
|
||||||
span,
|
span,
|
||||||
&mut err,
|
&mut err,
|
||||||
|
@ -533,6 +531,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.note_candidates_on_method_error(
|
self.note_candidates_on_method_error(
|
||||||
rcvr_ty,
|
rcvr_ty,
|
||||||
item_name,
|
item_name,
|
||||||
|
source,
|
||||||
args,
|
args,
|
||||||
span,
|
span,
|
||||||
&mut err,
|
&mut err,
|
||||||
|
@ -976,7 +975,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
unsatisfied_bounds = true;
|
unsatisfied_bounds = true;
|
||||||
}
|
}
|
||||||
} else if let ty::Adt(def, targs) = rcvr_ty.kind()
|
} else if let ty::Adt(def, targs) = rcvr_ty.kind()
|
||||||
&& let Some(args) = args
|
&& let SelfSource::MethodCall(rcvr_expr) = source
|
||||||
{
|
{
|
||||||
// This is useful for methods on arbitrary self types that might have a simple
|
// This is useful for methods on arbitrary self types that might have a simple
|
||||||
// mutability difference, like calling a method on `Pin<&mut Self>` that is on
|
// mutability difference, like calling a method on `Pin<&mut Self>` that is on
|
||||||
|
@ -999,8 +998,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
rcvr_ty,
|
rcvr_ty,
|
||||||
&item_segment,
|
&item_segment,
|
||||||
span,
|
span,
|
||||||
args.full_expr,
|
tcx.hir().get_parent(rcvr_expr.hir_id).expect_expr(),
|
||||||
args.receiver,
|
rcvr_expr,
|
||||||
) {
|
) {
|
||||||
err.span_note(
|
err.span_note(
|
||||||
tcx.def_span(method.def_id),
|
tcx.def_span(method.def_id),
|
||||||
|
@ -1169,7 +1168,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
span,
|
span,
|
||||||
rcvr_ty,
|
rcvr_ty,
|
||||||
item_name,
|
item_name,
|
||||||
args.map(|MethodCallComponents { args, .. }| args.len() + 1),
|
args.map(|args| args.len() + 1),
|
||||||
source,
|
source,
|
||||||
no_match_data.out_of_scope_traits.clone(),
|
no_match_data.out_of_scope_traits.clone(),
|
||||||
&unsatisfied_predicates,
|
&unsatisfied_predicates,
|
||||||
|
@ -1250,7 +1249,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
&self,
|
&self,
|
||||||
rcvr_ty: Ty<'tcx>,
|
rcvr_ty: Ty<'tcx>,
|
||||||
item_name: Ident,
|
item_name: Ident,
|
||||||
args: Option<MethodCallComponents<'tcx>>,
|
self_source: SelfSource<'tcx>,
|
||||||
|
args: Option<&'tcx [hir::Expr<'tcx>]>,
|
||||||
span: Span,
|
span: Span,
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
sources: &mut Vec<CandidateSource>,
|
sources: &mut Vec<CandidateSource>,
|
||||||
|
@ -1320,40 +1320,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
if let Some(sugg_span) = sugg_span
|
if let Some(sugg_span) = sugg_span
|
||||||
&& let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did)
|
&& let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did)
|
||||||
{
|
&& let Some(sugg) = print_disambiguation_help(
|
||||||
let path = self.tcx.def_path_str(trait_ref.skip_binder().def_id);
|
self.tcx,
|
||||||
|
|
||||||
let ty = match item.kind {
|
|
||||||
ty::AssocKind::Const | ty::AssocKind::Type => impl_ty,
|
|
||||||
ty::AssocKind::Fn => self
|
|
||||||
.tcx
|
|
||||||
.fn_sig(item.def_id)
|
|
||||||
.instantiate_identity()
|
|
||||||
.inputs()
|
|
||||||
.skip_binder()
|
|
||||||
.get(0)
|
|
||||||
.filter(|ty| ty.is_ref() && !rcvr_ty.is_ref())
|
|
||||||
.copied()
|
|
||||||
.unwrap_or(rcvr_ty),
|
|
||||||
};
|
|
||||||
if let Some(sugg) = print_disambiguation_help(
|
|
||||||
item_name,
|
|
||||||
args,
|
|
||||||
err,
|
err,
|
||||||
path,
|
self_source,
|
||||||
ty,
|
args,
|
||||||
Some(impl_ty),
|
trait_ref.instantiate(
|
||||||
item.kind,
|
self.tcx,
|
||||||
self.tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id),
|
self.fresh_args_for_item(sugg_span, impl_did)
|
||||||
sugg_span,
|
).with_self_ty(self.tcx, rcvr_ty),
|
||||||
idx,
|
idx,
|
||||||
self.tcx.sess.source_map(),
|
sugg_span,
|
||||||
item.fn_has_self_parameter,
|
item,
|
||||||
) {
|
)
|
||||||
|
{
|
||||||
suggs.push(sugg);
|
suggs.push(sugg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
CandidateSource::Trait(trait_did) => {
|
CandidateSource::Trait(trait_did) => {
|
||||||
let Some(item) = self.associated_value(trait_did, item_name) else { continue };
|
let Some(item) = self.associated_value(trait_did, item_name) else { continue };
|
||||||
let item_span = self.tcx.def_span(item.def_id);
|
let item_span = self.tcx.def_span(item.def_id);
|
||||||
|
@ -1373,28 +1356,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
err.span_note(item_span, msg);
|
err.span_note(item_span, msg);
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
if let Some(sugg_span) = sugg_span {
|
if let Some(sugg_span) = sugg_span
|
||||||
let path = self.tcx.def_path_str(trait_did);
|
&& let Some(sugg) = print_disambiguation_help(
|
||||||
if let Some(sugg) = print_disambiguation_help(
|
self.tcx,
|
||||||
item_name,
|
|
||||||
args,
|
|
||||||
err,
|
err,
|
||||||
path,
|
self_source,
|
||||||
rcvr_ty,
|
args,
|
||||||
None,
|
ty::TraitRef::new(
|
||||||
item.kind,
|
self.tcx,
|
||||||
self.tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id),
|
trait_did,
|
||||||
sugg_span,
|
self.fresh_args_for_item(sugg_span, trait_did)
|
||||||
|
).with_self_ty(self.tcx, rcvr_ty),
|
||||||
idx,
|
idx,
|
||||||
self.tcx.sess.source_map(),
|
sugg_span,
|
||||||
item.fn_has_self_parameter,
|
item,
|
||||||
) {
|
)
|
||||||
|
{
|
||||||
suggs.push(sugg);
|
suggs.push(sugg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if !suggs.is_empty() && let Some(span) = sugg_span {
|
if !suggs.is_empty() && let Some(span) = sugg_span {
|
||||||
err.span_suggestions(
|
err.span_suggestions(
|
||||||
span.with_hi(item_name.span.lo()),
|
span.with_hi(item_name.span.lo()),
|
||||||
|
@ -1410,18 +1392,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
/// Look at all the associated functions without receivers in the type's inherent impls
|
/// Look at all the associated functions without receivers in the type's inherent impls
|
||||||
/// to look for builders that return `Self`, `Option<Self>` or `Result<Self, _>`.
|
/// to look for builders that return `Self`, `Option<Self>` or `Result<Self, _>`.
|
||||||
fn find_builder_fn(&self, err: &mut Diagnostic, rcvr_ty: Ty<'tcx>, source: SelfSource<'tcx>) {
|
fn find_builder_fn(&self, err: &mut Diagnostic, rcvr_ty: Ty<'tcx>) {
|
||||||
let ty::Adt(adt_def, _) = rcvr_ty.kind() else {
|
let ty::Adt(adt_def, _) = rcvr_ty.kind() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let SelfSource::QPath(ty) = source else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let hir = self.tcx.hir();
|
|
||||||
if let Some(Node::Pat(_)) = hir.find(hir.parent_id(ty.hir_id)) {
|
|
||||||
// Do not suggest a fn call when a pattern is expected.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let mut items = self
|
let mut items = self
|
||||||
.tcx
|
.tcx
|
||||||
.inherent_impls(adt_def.did())
|
.inherent_impls(adt_def.did())
|
||||||
|
@ -1504,7 +1478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
rcvr_ty: Ty<'tcx>,
|
rcvr_ty: Ty<'tcx>,
|
||||||
source: SelfSource<'tcx>,
|
source: SelfSource<'tcx>,
|
||||||
item_name: Ident,
|
item_name: Ident,
|
||||||
args: Option<MethodCallComponents<'tcx>>,
|
args: Option<&'tcx [hir::Expr<'tcx>]>,
|
||||||
sugg_span: Span,
|
sugg_span: Span,
|
||||||
) {
|
) {
|
||||||
let mut has_unsuggestable_args = false;
|
let mut has_unsuggestable_args = false;
|
||||||
|
@ -1578,7 +1552,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
let args = if let Some(MethodCallComponents { receiver, args, .. }) = args {
|
let args = if let SelfSource::MethodCall(receiver) = source
|
||||||
|
&& let Some(args) = args
|
||||||
|
{
|
||||||
// The first arg is the same kind as the receiver
|
// The first arg is the same kind as the receiver
|
||||||
let explicit_args = if first_arg.is_some() {
|
let explicit_args = if first_arg.is_some() {
|
||||||
std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>()
|
std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>()
|
||||||
|
@ -3267,56 +3243,59 @@ pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_disambiguation_help<'tcx>(
|
fn print_disambiguation_help<'tcx>(
|
||||||
item_name: Ident,
|
tcx: TyCtxt<'tcx>,
|
||||||
args: Option<MethodCallComponents<'tcx>>,
|
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
trait_name: String,
|
source: SelfSource<'tcx>,
|
||||||
rcvr_ty: Ty<'_>,
|
args: Option<&'tcx [hir::Expr<'tcx>]>,
|
||||||
impl_self_ty: Option<Ty<'_>>,
|
trait_ref: ty::TraitRef<'tcx>,
|
||||||
kind: ty::AssocKind,
|
candidate_idx: Option<usize>,
|
||||||
def_kind_descr: &'static str,
|
|
||||||
span: Span,
|
span: Span,
|
||||||
candidate: Option<usize>,
|
item: ty::AssocItem,
|
||||||
source_map: &source_map::SourceMap,
|
|
||||||
fn_has_self_parameter: bool,
|
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
|
let trait_ref = if item.fn_has_self_parameter {
|
||||||
|
trait_ref.print_only_trait_name().to_string()
|
||||||
|
} else {
|
||||||
|
format!("<{} as {}>", trait_ref.args[0], trait_ref.print_only_trait_name())
|
||||||
|
};
|
||||||
Some(
|
Some(
|
||||||
if let (ty::AssocKind::Fn, Some(MethodCallComponents { receiver, args, .. })) = (kind, args)
|
if matches!(item.kind, ty::AssocKind::Fn)
|
||||||
|
&& let SelfSource::MethodCall(receiver) = source
|
||||||
|
&& let Some(args) = args
|
||||||
{
|
{
|
||||||
|
let def_kind_descr = tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id);
|
||||||
|
let item_name = item.ident(tcx);
|
||||||
|
let rcvr_ref = tcx.fn_sig(item.def_id).skip_binder().skip_binder().inputs()[0]
|
||||||
|
.ref_mutability()
|
||||||
|
.map_or("", |mutbl| mutbl.ref_prefix_str());
|
||||||
let args = format!(
|
let args = format!(
|
||||||
"({}{})",
|
"({}{})",
|
||||||
rcvr_ty.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()),
|
rcvr_ref,
|
||||||
std::iter::once(receiver)
|
std::iter::once(receiver)
|
||||||
.chain(args.iter())
|
.chain(args.iter())
|
||||||
.map(|arg| source_map
|
.map(|arg| tcx
|
||||||
|
.sess
|
||||||
|
.source_map()
|
||||||
.span_to_snippet(arg.span)
|
.span_to_snippet(arg.span)
|
||||||
.unwrap_or_else(|_| { "_".to_owned() }))
|
.unwrap_or_else(|_| { "_".to_owned() }))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(", "),
|
.join(", "),
|
||||||
);
|
);
|
||||||
let trait_name = if !fn_has_self_parameter && let Some(impl_self_ty) = impl_self_ty {
|
|
||||||
format!("<{impl_self_ty} as {trait_name}>")
|
|
||||||
} else {
|
|
||||||
trait_name
|
|
||||||
};
|
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
span,
|
span,
|
||||||
format!(
|
format!(
|
||||||
"disambiguate the {def_kind_descr} for {}",
|
"disambiguate the {def_kind_descr} for {}",
|
||||||
if let Some(candidate) = candidate {
|
if let Some(candidate) = candidate_idx {
|
||||||
format!("candidate #{candidate}")
|
format!("candidate #{candidate}")
|
||||||
} else {
|
} else {
|
||||||
"the candidate".to_string()
|
"the candidate".to_string()
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
format!("{trait_name}::{item_name}{args}"),
|
format!("{trait_ref}::{item_name}{args}"),
|
||||||
Applicability::HasPlaceholders,
|
Applicability::HasPlaceholders,
|
||||||
);
|
);
|
||||||
return None;
|
return None;
|
||||||
} else if let Some(impl_self_ty) = impl_self_ty {
|
|
||||||
format!("<{impl_self_ty} as {trait_name}>::")
|
|
||||||
} else {
|
} else {
|
||||||
format!("{trait_name}::")
|
format!("{trait_ref}::")
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,9 +166,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) {
|
fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) {
|
||||||
let PatInfo { binding_mode: def_bm, top_info: ti, .. } = pat_info;
|
let PatInfo { binding_mode: def_bm, top_info: ti, .. } = pat_info;
|
||||||
let path_res = match &pat.kind {
|
let path_res = match &pat.kind {
|
||||||
PatKind::Path(qpath) => {
|
PatKind::Path(qpath) => Some(
|
||||||
Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span))
|
self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span, None),
|
||||||
}
|
),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
|
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
|
||||||
|
@ -1060,7 +1060,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
// Resolve the path and check the definition for errors.
|
// Resolve the path and check the definition for errors.
|
||||||
let (res, opt_ty, segments) =
|
let (res, opt_ty, segments) =
|
||||||
self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span);
|
self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span, None);
|
||||||
if res == Res::Err {
|
if res == Res::Err {
|
||||||
let e = tcx.sess.delay_span_bug(pat.span, "`Res::Err` but no error emitted");
|
let e = tcx.sess.delay_span_bug(pat.span, "`Res::Err` but no error emitted");
|
||||||
self.set_tainted_by_errors(e);
|
self.set_tainted_by_errors(e);
|
||||||
|
|
|
@ -29,10 +29,10 @@ LL | fn foo(&self) {}
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
help: use fully-qualified syntax to disambiguate
|
help: use fully-qualified syntax to disambiguate
|
||||||
|
|
|
|
||||||
LL | <T as A>::foo(&s);
|
LL | A::foo(&s);
|
||||||
| ~~~~~~~~~~
|
| ~~~
|
||||||
LL | <T as B>::foo(&s);
|
LL | B::foo(&s);
|
||||||
| ~~~~~~~~~~
|
| ~~~
|
||||||
|
|
||||||
error[E0034]: multiple applicable items in scope
|
error[E0034]: multiple applicable items in scope
|
||||||
--> $DIR/disambiguate-multiple-blanket-impl.rs:33:8
|
--> $DIR/disambiguate-multiple-blanket-impl.rs:33:8
|
||||||
|
@ -52,9 +52,9 @@ LL | const CONST: usize = 2;
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
help: use fully-qualified syntax to disambiguate
|
help: use fully-qualified syntax to disambiguate
|
||||||
|
|
|
|
||||||
LL | <T as A>::CONST;
|
LL | <S as A>::CONST;
|
||||||
| ~~~~~~~~~~
|
| ~~~~~~~~~~
|
||||||
LL | <T as B>::CONST;
|
LL | <S as B>::CONST;
|
||||||
| ~~~~~~~~~~
|
| ~~~~~~~~~~
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
|
@ -29,10 +29,10 @@ LL | fn foo(&self) {}
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
help: use fully-qualified syntax to disambiguate
|
help: use fully-qualified syntax to disambiguate
|
||||||
|
|
|
|
||||||
LL | <S as A>::foo(&s);
|
LL | A::foo(&s);
|
||||||
| ~~~~~~~~~~
|
| ~~~
|
||||||
LL | <S as B>::foo(&s);
|
LL | B::foo(&s);
|
||||||
| ~~~~~~~~~~
|
| ~~~
|
||||||
|
|
||||||
error[E0034]: multiple applicable items in scope
|
error[E0034]: multiple applicable items in scope
|
||||||
--> $DIR/disambiguate-multiple-impl.rs:34:16
|
--> $DIR/disambiguate-multiple-impl.rs:34:16
|
||||||
|
|
|
@ -37,12 +37,12 @@ LL | fn foo(&self);
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
help: disambiguate the method for candidate #1
|
help: disambiguate the method for candidate #1
|
||||||
|
|
|
|
||||||
LL | A::foo(t);
|
LL | A::foo(&t);
|
||||||
| ~~~~~~~~~
|
| ~~~~~~~~~~
|
||||||
help: disambiguate the method for candidate #2
|
help: disambiguate the method for candidate #2
|
||||||
|
|
|
|
||||||
LL | B::foo(t);
|
LL | B::foo(&t);
|
||||||
| ~~~~~~~~~
|
| ~~~~~~~~~~
|
||||||
|
|
||||||
error[E0034]: multiple applicable items in scope
|
error[E0034]: multiple applicable items in scope
|
||||||
--> $DIR/disambiguate-multiple-trait-2.rs:20:16
|
--> $DIR/disambiguate-multiple-trait-2.rs:20:16
|
||||||
|
@ -62,10 +62,10 @@ LL | const CONST: usize;
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
help: use fully-qualified syntax to disambiguate
|
help: use fully-qualified syntax to disambiguate
|
||||||
|
|
|
|
||||||
LL | let _ = A::CONST;
|
LL | let _ = <T as A>::CONST;
|
||||||
| ~~~
|
| ~~~~~~~~~~
|
||||||
LL | let _ = B::CONST;
|
LL | let _ = <T as B>::CONST;
|
||||||
| ~~~
|
| ~~~~~~~~~~
|
||||||
|
|
||||||
error[E0223]: ambiguous associated type
|
error[E0223]: ambiguous associated type
|
||||||
--> $DIR/disambiguate-multiple-trait-2.rs:52:12
|
--> $DIR/disambiguate-multiple-trait-2.rs:52:12
|
||||||
|
@ -98,10 +98,10 @@ LL | fn foo(&self) {}
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
help: use fully-qualified syntax to disambiguate
|
help: use fully-qualified syntax to disambiguate
|
||||||
|
|
|
|
||||||
LL | <T as A>::foo(&s);
|
LL | A::foo(&s);
|
||||||
| ~~~~~~~~~~
|
| ~~~
|
||||||
LL | <T as B>::foo(&s);
|
LL | B::foo(&s);
|
||||||
| ~~~~~~~~~~
|
| ~~~
|
||||||
|
|
||||||
error[E0034]: multiple applicable items in scope
|
error[E0034]: multiple applicable items in scope
|
||||||
--> $DIR/disambiguate-multiple-trait-2.rs:49:16
|
--> $DIR/disambiguate-multiple-trait-2.rs:49:16
|
||||||
|
@ -121,9 +121,9 @@ LL | const CONST: usize = 1;
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
help: use fully-qualified syntax to disambiguate
|
help: use fully-qualified syntax to disambiguate
|
||||||
|
|
|
|
||||||
LL | let _ = <T as A>::CONST;
|
LL | let _ = <S as A>::CONST;
|
||||||
| ~~~~~~~~~~
|
| ~~~~~~~~~~
|
||||||
LL | let _ = <T as B>::CONST;
|
LL | let _ = <S as B>::CONST;
|
||||||
| ~~~~~~~~~~
|
| ~~~~~~~~~~
|
||||||
|
|
||||||
error: aborting due to 6 previous errors
|
error: aborting due to 6 previous errors
|
||||||
|
|
|
@ -29,10 +29,10 @@ LL | fn foo(&self) {}
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
help: use fully-qualified syntax to disambiguate
|
help: use fully-qualified syntax to disambiguate
|
||||||
|
|
|
|
||||||
LL | <T as A>::foo(&s);
|
LL | A::foo(&s);
|
||||||
| ~~~~~~~~~~
|
| ~~~
|
||||||
LL | <T as B>::foo(&s);
|
LL | B::foo(&s);
|
||||||
| ~~~~~~~~~~
|
| ~~~
|
||||||
|
|
||||||
error[E0034]: multiple applicable items in scope
|
error[E0034]: multiple applicable items in scope
|
||||||
--> $DIR/disambiguate-multiple-trait.rs:27:16
|
--> $DIR/disambiguate-multiple-trait.rs:27:16
|
||||||
|
@ -52,9 +52,9 @@ LL | const CONST: usize = 2;
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
help: use fully-qualified syntax to disambiguate
|
help: use fully-qualified syntax to disambiguate
|
||||||
|
|
|
|
||||||
LL | let _ = <T as A>::CONST;
|
LL | let _ = <S as A>::CONST;
|
||||||
| ~~~~~~~~~~
|
| ~~~~~~~~~~
|
||||||
LL | let _ = <T as B>::CONST;
|
LL | let _ = <S as B>::CONST;
|
||||||
| ~~~~~~~~~~
|
| ~~~~~~~~~~
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
|
@ -16,12 +16,12 @@ LL | trait B { fn foo(&self); }
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
help: disambiguate the method for candidate #1
|
help: disambiguate the method for candidate #1
|
||||||
|
|
|
|
||||||
LL | A::foo(t);
|
LL | A::foo(&t);
|
||||||
| ~~~~~~~~~
|
| ~~~~~~~~~~
|
||||||
help: disambiguate the method for candidate #2
|
help: disambiguate the method for candidate #2
|
||||||
|
|
|
|
||||||
LL | B::foo(t);
|
LL | B::foo(&t);
|
||||||
| ~~~~~~~~~
|
| ~~~~~~~~~~
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -54,8 +54,8 @@ LL | let z = NuisanceFoo::foo(x);
|
||||||
| ~~~~~~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~~~~~~
|
||||||
help: disambiguate the method for candidate #3
|
help: disambiguate the method for candidate #3
|
||||||
|
|
|
|
||||||
LL | let z = FinalFoo::foo(x);
|
LL | let z = FinalFoo::foo(&x);
|
||||||
| ~~~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:139:24
|
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:139:24
|
||||||
|
|
|
@ -16,12 +16,12 @@ LL | fn foo(&mut self) {}
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
help: disambiguate the method for candidate #1
|
help: disambiguate the method for candidate #1
|
||||||
|
|
|
|
||||||
LL | A::foo(&a)
|
LL | A::foo(&mut a)
|
||||||
| ~~~~~~~~~~
|
| ~~~~~~~~~~~~~~
|
||||||
help: disambiguate the method for candidate #2
|
help: disambiguate the method for candidate #2
|
||||||
|
|
|
|
||||||
LL | B::foo(&a)
|
LL | B::foo(&mut a)
|
||||||
| ~~~~~~~~~~
|
| ~~~~~~~~~~~~~~
|
||||||
|
|
||||||
error[E0034]: multiple applicable items in scope
|
error[E0034]: multiple applicable items in scope
|
||||||
--> $DIR/issue-37767.rs:22:7
|
--> $DIR/issue-37767.rs:22:7
|
||||||
|
|
Loading…
Add table
Reference in a new issue