use crate::check::cast;
use crate::check::coercion::CoerceMany;
use crate::check::fatally_break_rust;
-use crate::check::method::{probe, MethodError, SelfSource};
+use crate::check::method::SelfSource;
use crate::check::report_unexpected_variant_res;
use crate::check::BreakableCtxt;
use crate::check::Diverges;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items::LangItem;
use rustc_hir::{ExprKind, QPath};
use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id).1
}
- fn check_expr_path(&self, qpath: &hir::QPath<'_>, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> {
+ fn check_expr_path(
+ &self,
+ qpath: &'tcx hir::QPath<'tcx>,
+ expr: &'tcx hir::Expr<'tcx>,
+ ) -> Ty<'tcx> {
let tcx = self.tcx;
let (res, opt_ty, segs) = self.resolve_ty_and_res_ufcs(qpath, expr.hir_id, expr.span);
let ty = match res {
}
Err(error) => {
if segment.ident.name != kw::Empty {
- self.report_extended_method_error(segment, span, args, rcvr_t, error);
+ if let Some(mut err) = self.report_method_error(
+ span,
+ rcvr_t,
+ segment.ident,
+ SelfSource::MethodCall(&args[0]),
+ error,
+ Some(args),
+ ) {
+ err.emit();
+ }
}
Err(())
}
)
}
- fn report_extended_method_error(
- &self,
- segment: &hir::PathSegment<'_>,
- span: Span,
- args: &'tcx [hir::Expr<'tcx>],
- rcvr_t: Ty<'tcx>,
- error: MethodError<'tcx>,
- ) {
- let rcvr = &args[0];
- let try_alt_rcvr = |err: &mut DiagnosticBuilder<'_>, new_rcvr_t, pre: &str, post: &str| {
- if let Some(new_rcvr_t) = new_rcvr_t {
- if let Ok(pick) = self.lookup_probe(
- span,
- segment.ident,
- new_rcvr_t,
- rcvr,
- probe::ProbeScope::AllTraits,
- ) {
- debug!("try_alt_rcvr: pick candidate {:?}", pick);
- // Make sure the method is defined for the *actual* receiver:
- // we don't want to treat `Box<Self>` as a receiver if
- // it only works because of an autoderef to `&self`
- if pick.autoderefs == 0
- // We don't want to suggest a container type when the missing method is
- // `.clone()`, otherwise we'd suggest `Arc::new(foo).clone()`, which is
- // far from what the user really wants.
- && Some(pick.item.container.id()) != self.tcx.lang_items().clone_trait()
- {
- err.span_label(
- pick.item.ident.span,
- &format!("the method is available for `{}` here", new_rcvr_t),
- );
- err.multipart_suggestion(
- "consider wrapping the receiver expression with the appropriate type",
- vec![
- (rcvr.span.shrink_to_lo(), format!("{}({}", pre, post)),
- (rcvr.span.shrink_to_hi(), ")".to_string()),
- ],
- Applicability::MaybeIncorrect,
- );
- }
- }
- }
- };
-
- if let Some(mut err) = self.report_method_error(
- span,
- rcvr_t,
- segment.ident,
- SelfSource::MethodCall(rcvr),
- error,
- Some(args),
- ) {
- if let ty::Adt(..) = rcvr_t.kind() {
- // Try alternative arbitrary self types that could fulfill this call.
- // FIXME: probe for all types that *could* be arbitrary self-types, not
- // just this list.
- for (rcvr_t, post) in &[
- (rcvr_t, ""),
- (self.tcx.mk_mut_ref(&ty::ReErased, rcvr_t), "&mut "),
- (self.tcx.mk_imm_ref(&ty::ReErased, rcvr_t), "&"),
- ] {
- for (rcvr_t, pre) in &[
- (self.tcx.mk_lang_item(rcvr_t, LangItem::OwnedBox), "Box::new"),
- (self.tcx.mk_lang_item(rcvr_t, LangItem::Pin), "Pin::new"),
- (self.tcx.mk_diagnostic_item(rcvr_t, sym::Arc), "Arc::new"),
- (self.tcx.mk_diagnostic_item(rcvr_t, sym::Rc), "Rc::new"),
- ] {
- try_alt_rcvr(&mut err, *rcvr_t, pre, post);
- }
- }
- }
- err.emit();
- }
- }
-
fn check_expr_cast(
&self,
e: &'tcx hir::Expr<'tcx>,
/// Resolves an associated value path into a base type and associated constant, or method
/// resolution. The newly resolved definition is written into `type_dependent_defs`.
- pub fn resolve_ty_and_res_ufcs<'b>(
+ pub fn resolve_ty_and_res_ufcs(
&self,
- qpath: &'b QPath<'b>,
+ qpath: &'tcx QPath<'tcx>,
hir_id: hir::HirId,
span: Span,
- ) -> (Res, Option<Ty<'tcx>>, &'b [hir::PathSegment<'b>]) {
+ ) -> (Res, Option<Ty<'tcx>>, &'tcx [hir::PathSegment<'tcx>]) {
debug!("resolve_ty_and_res_ufcs: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span);
let (ty, qself, item_segment) = match *qpath {
QPath::Resolved(ref opt_qself, ref path) => {
}
}
- pub fn report_method_error<'b>(
+ pub fn report_method_error(
&self,
span: Span,
rcvr_ty: Ty<'tcx>,
item_name: Ident,
- source: SelfSource<'b>,
+ source: SelfSource<'tcx>,
error: MethodError<'tcx>,
args: Option<&'tcx [hir::Expr<'tcx>]>,
) -> Option<DiagnosticBuilder<'_>> {
err.span_suggestion(
lit.span,
&format!(
- "you must specify a concrete type for \
- this numeric value, like `{}`",
+ "you must specify a concrete type for this numeric value, \
+ like `{}`",
concrete_type
),
format!("{}_{}", snippet, concrete_type),
}
}
- fn suggest_traits_to_import<'b>(
+ fn suggest_traits_to_import(
&self,
err: &mut DiagnosticBuilder<'_>,
span: Span,
rcvr_ty: Ty<'tcx>,
item_name: Ident,
- source: SelfSource<'b>,
+ source: SelfSource<'tcx>,
valid_out_of_scope_traits: Vec<DefId>,
unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)],
) {
- if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
+ let mut alt_rcvr_sugg = false;
+ if let SelfSource::MethodCall(rcvr) = source {
+ info!(?span, ?item_name, ?rcvr_ty, ?rcvr);
+ if let ty::Adt(..) = rcvr_ty.kind() {
+ // Try alternative arbitrary self types that could fulfill this call.
+ // FIXME: probe for all types that *could* be arbitrary self-types, not
+ // just this list.
+ for (rcvr_ty, post) in &[
+ (rcvr_ty, ""),
+ (self.tcx.mk_mut_ref(&ty::ReErased, rcvr_ty), "&mut "),
+ (self.tcx.mk_imm_ref(&ty::ReErased, rcvr_ty), "&"),
+ ] {
+ for (rcvr_ty, pre) in &[
+ (self.tcx.mk_lang_item(rcvr_ty, LangItem::OwnedBox), "Box::new"),
+ (self.tcx.mk_lang_item(rcvr_ty, LangItem::Pin), "Pin::new"),
+ (self.tcx.mk_diagnostic_item(rcvr_ty, sym::Arc), "Arc::new"),
+ (self.tcx.mk_diagnostic_item(rcvr_ty, sym::Rc), "Rc::new"),
+ ] {
+ if let Some(new_rcvr_t) = *rcvr_ty {
+ if let Ok(pick) = self.lookup_probe(
+ span,
+ item_name,
+ new_rcvr_t,
+ rcvr,
+ crate::check::method::probe::ProbeScope::AllTraits,
+ ) {
+ debug!("try_alt_rcvr: pick candidate {:?}", pick);
+ // Make sure the method is defined for the *actual* receiver:
+ // we don't want to treat `Box<Self>` as a receiver if
+ // it only works because of an autoderef to `&self`
+ if pick.autoderefs == 0
+ // We don't want to suggest a container type when the missing method is
+ // `.clone()`, otherwise we'd suggest `Arc::new(foo).clone()`, which is
+ // far from what the user really wants.
+ && Some(pick.item.container.id()) != self.tcx.lang_items().clone_trait()
+ {
+ err.span_label(
+ pick.item.ident.span,
+ &format!(
+ "the method is available for `{}` here",
+ new_rcvr_t
+ ),
+ );
+ err.multipart_suggestion(
+ "consider wrapping the receiver expression with the \
+ appropriate type",
+ vec![
+ (rcvr.span.shrink_to_lo(), format!("{}({}", pre, post)),
+ (rcvr.span.shrink_to_hi(), ")".to_string()),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ // We don't care about the other suggestions.
+ alt_rcvr_sugg = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if !alt_rcvr_sugg && self.suggest_valid_traits(err, valid_out_of_scope_traits) {
return;
}
"the method might not be found because of this arbitrary self type",
);
}
+ if alt_rcvr_sugg {
+ return;
+ }
if !candidates.is_empty() {
// Sort from most relevant to least relevant.
/// Checks whether there is a local type somewhere in the chain of
/// autoderefs of `rcvr_ty`.
- fn type_derefs_to_local(&self, span: Span, rcvr_ty: Ty<'tcx>, source: SelfSource<'_>) -> bool {
+ fn type_derefs_to_local(
+ &self,
+ span: Span,
+ rcvr_ty: Ty<'tcx>,
+ source: SelfSource<'tcx>,
+ ) -> bool {
fn is_local(ty: Ty<'_>) -> bool {
match ty.kind() {
ty::Adt(def, _) => def.did.is_local(),
}
}
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
pub enum SelfSource<'a> {
QPath(&'a hir::Ty<'a>),
MethodCall(&'a hir::Expr<'a> /* rcvr */),
fn check_pat_tuple_struct(
&self,
pat: &'tcx Pat<'tcx>,
- qpath: &hir::QPath<'_>,
+ qpath: &'tcx hir::QPath<'tcx>,
subpats: &'tcx [&'tcx Pat<'tcx>],
ddpos: Option<usize>,
expected: Ty<'tcx>,
LL | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
| ---- the method is available for `Pin<&mut Sleep>` here
|
- = help: items from traits can only be used if the trait is implemented and in scope
- = note: the following trait defines an item `poll`, perhaps you need to implement it:
- candidate #1: `Future`
help: consider wrapping the receiver expression with the appropriate type
|
LL | Pin::new(&mut self.sleep).poll(cx)