diff options
| author | bors <bors@rust-lang.org> | 2021-03-30 11:44:36 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-03-30 11:44:36 +0000 |
| commit | 16156fb2787f745e57504197bd7fe38b69c6cbea (patch) | |
| tree | 8629975b2f2fb968c84444d7090f746f0a7a98e2 /compiler | |
| parent | 689e8470ffa7aeca17cfee428704a4d6c4148c11 (diff) | |
| parent | 5b467787b625d83d5cf210e70d56487e53ce4255 (diff) | |
| download | rust-16156fb2787f745e57504197bd7fe38b69c6cbea.tar.gz rust-16156fb2787f745e57504197bd7fe38b69c6cbea.zip | |
Auto merge of #83674 - Dylan-DPC:rollup-bcuc1hl, r=Dylan-DPC
Rollup of 7 pull requests Successful merges: - #83568 (update comment at MaybeUninit::uninit_array) - #83571 (Constantify some slice methods) - #83579 (Improve pointer arithmetic docs) - #83645 (Wrap non-pre code blocks) - #83656 (Add a regression test for issue-82865) - #83662 (Update books) - #83667 (Suggest box/pin/arc ing receiver on method calls) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_typeck/src/check/expr.rs | 73 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/method/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/method/suggest.rs | 87 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/pat.rs | 2 |
5 files changed, 100 insertions, 70 deletions
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 8951c08bd33..30d60514063 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -6,7 +6,7 @@ use crate::astconv::AstConv as _; 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; @@ -30,7 +30,6 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, 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}; @@ -461,7 +460,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 { @@ -947,7 +950,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } 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(()) } @@ -964,59 +976,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) } - 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| { - 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 { - err.span_label( - pick.item.ident.span, - &format!("the method is available for `{}` here", new_rcvr_t), - ); - } - } - } - }; - - 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. - try_alt_rcvr(&mut err, self.tcx.mk_lang_item(rcvr_t, LangItem::OwnedBox)); - try_alt_rcvr(&mut err, self.tcx.mk_lang_item(rcvr_t, LangItem::Pin)); - try_alt_rcvr(&mut err, self.tcx.mk_diagnostic_item(rcvr_t, sym::Arc)); - try_alt_rcvr(&mut err, self.tcx.mk_diagnostic_item(rcvr_t, sym::Rc)); - } - err.emit(); - } - } - fn check_expr_cast( &self, e: &'tcx hir::Expr<'tcx>, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index e64d8367676..a7a412f06be 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -905,12 +905,12 @@ impl<'a, 'tcx> FnCtxt<'a, '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) => { diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index d6fa6bf0067..c74fd25f76d 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -45,6 +45,7 @@ pub struct MethodCallee<'tcx> { pub sig: ty::FnSig<'tcx>, } +#[derive(Debug)] pub enum MethodError<'tcx> { // Did not find an applicable method, but we did find various near-misses that may work. NoMatch(NoMatchData<'tcx>), @@ -66,6 +67,7 @@ pub enum MethodError<'tcx> { // Contains a list of static methods that may apply, a list of unsatisfied trait predicates which // could lead to matches if satisfied, and a list of not-in-scope traits which may work. +#[derive(Debug)] pub struct NoMatchData<'tcx> { pub static_candidates: Vec<CandidateSource>, pub unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>, diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 13757ac4132..72eff009473 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -68,12 +68,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - 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<'_>> { @@ -323,8 +323,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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), @@ -975,17 +975,78 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - 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; } @@ -1075,6 +1136,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "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. @@ -1284,7 +1348,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// 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(), @@ -1310,7 +1379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub enum SelfSource<'a> { QPath(&'a hir::Ty<'a>), MethodCall(&'a hir::Expr<'a> /* rcvr */), diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 79c544bd386..53593b9bab4 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -861,7 +861,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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>, |
