Skip to content

Commit

Permalink
Auto merge of #83674 - Dylan-DPC:rollup-bcuc1hl, r=Dylan-DPC
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Mar 30, 2021
2 parents 689e847 + 5b46778 commit 16156fb
Show file tree
Hide file tree
Showing 33 changed files with 287 additions and 233 deletions.
73 changes: 16 additions & 57 deletions compiler/rustc_typeck/src/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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};
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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(())
}
Expand All @@ -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>,
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_typeck/src/check/method/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>),
Expand All @@ -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>>)>,
Expand Down
87 changes: 78 additions & 9 deletions compiler/rustc_typeck/src/check/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<'_>> {
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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(),
Expand All @@ -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 */),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down
6 changes: 3 additions & 3 deletions library/core/src/mem/maybe_uninit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,9 +319,9 @@ impl<T> MaybeUninit<T> {
/// Create a new array of `MaybeUninit<T>` items, in an uninitialized state.
///
/// Note: in a future Rust version this method may become unnecessary
/// when array literal syntax allows
/// [repeating const expressions](https://github.com/rust-lang/rust/issues/49147).
/// The example below could then use `let mut buf = [MaybeUninit::<u8>::uninit(); 32];`.
/// when Rust allows
/// [inline const expressions](https://github.com/rust-lang/rust/issues/76001).
/// The example below could then use `let mut buf = [const { MaybeUninit::<u8>::uninit() }; 32];`.
///
/// # Examples
///
Expand Down
Loading

0 comments on commit 16156fb

Please sign in to comment.